Fmts and clippies

This commit is contained in:
Pranav Gaddamadugu 2023-03-26 23:18:03 -07:00
parent 47e81a5d15
commit 8adc6c76b8
102 changed files with 839 additions and 1685 deletions

View File

@ -26,17 +26,8 @@ use walkdir::WalkDir;
const EXPECTED_LICENSE_TEXT: &str = include_str!(".resources/license_header"); const EXPECTED_LICENSE_TEXT: &str = include_str!(".resources/license_header");
// The following directories will be excluded from the license scan. // The following directories will be excluded from the license scan.
const DIRS_TO_SKIP: [&str; 9] = [ const DIRS_TO_SKIP: [&str; 9] =
".cargo", [".cargo", ".circleci", ".git", ".github", ".resources", "docs", "examples", "target", "tests"];
".circleci",
".git",
".github",
".resources",
"docs",
"examples",
"target",
"tests",
];
fn compare_license_text(path: &Path, expected_lines: &[&str]) { fn compare_license_text(path: &Path, expected_lines: &[&str]) {
let file = File::open(path).unwrap(); let file = File::open(path).unwrap();

View File

@ -29,10 +29,7 @@ pub fn serialize<S: Serializer>(
let joined: IndexMap<String, DefinitionStatement> = global_consts let joined: IndexMap<String, DefinitionStatement> = global_consts
.into_iter() .into_iter()
.map(|(idents, program)| { .map(|(idents, program)| {
( (idents.iter().map(|i| i.name.to_string()).collect::<Vec<_>>().join(","), program.clone())
idents.iter().map(|i| i.name.to_string()).collect::<Vec<_>>().join(","),
program.clone(),
)
}) })
.collect(); .collect();
@ -47,10 +44,7 @@ pub fn deserialize<'de, D: Deserializer<'de>>(
.map(|(name, program)| { .map(|(name, program)| {
( (
name.split(',') name.split(',')
.map(|ident_name| Identifier { .map(|ident_name| Identifier { name: Symbol::intern(ident_name), span: Default::default() })
name: Symbol::intern(ident_name),
span: Default::default(),
})
.collect::<Vec<Identifier>>(), .collect::<Vec<Identifier>>(),
program, program,
) )

View File

@ -20,9 +20,13 @@ use leo_span::{Span, Symbol};
use crate::{simple_node_impl, Node}; use crate::{simple_node_impl, Node};
use serde::{ use serde::{
de::{ de::{
Visitor, {self}, Visitor,
{self},
}, },
Deserialize, Deserializer, Serialize, Serializer, Deserialize,
Deserializer,
Serialize,
Serializer,
}; };
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
@ -48,10 +52,7 @@ simple_node_impl!(Identifier);
impl Identifier { impl Identifier {
/// Constructs a new identifier with `name` and a default span. /// Constructs a new identifier with `name` and a default span.
pub fn new(name: Symbol) -> Self { pub fn new(name: Symbol) -> Self {
Self { Self { name, span: Span::default() }
name,
span: Span::default(),
}
} }
/// Check if the Identifier name matches the other name. /// Check if the Identifier name matches the other name.

View File

@ -30,10 +30,7 @@ pub fn serialize<S: Serializer>(
imported_modules imported_modules
.into_iter() .into_iter()
.map(|(package, program)| { .map(|(package, program)| {
let package = package let package = package.iter().map(|x| x.as_str(s, |s| s.to_owned())).collect::<Vec<_>>();
.iter()
.map(|x| x.as_str(s, |s| s.to_owned()))
.collect::<Vec<_>>();
(package.join("."), program.clone()) (package.join("."), program.clone())
}) })
.collect() .collect()

View File

@ -15,8 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::fmt; use std::{fmt, str::FromStr};
use std::str::FromStr;
/// A number string guaranteed to be positive. /// A number string guaranteed to be positive.
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)] #[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]

View File

@ -86,42 +86,38 @@ pub enum BinaryOperation {
impl fmt::Display for BinaryOperation { impl fmt::Display for BinaryOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "{}", match self {
f, Self::Add => "+",
"{}", Self::AddWrapped => "add_wrapped",
match self { Self::And => "&&",
Self::Add => "+", Self::BitwiseAnd => "&",
Self::AddWrapped => "add_wrapped", Self::Div => "/",
Self::And => "&&", Self::DivWrapped => "div_wrapped",
Self::BitwiseAnd => "&", Self::Eq => "==",
Self::Div => "/", Self::Gte => ">=",
Self::DivWrapped => "div_wrapped", Self::Gt => ">",
Self::Eq => "==", Self::Lte => "<=",
Self::Gte => ">=", Self::Lt => "<",
Self::Gt => ">", Self::Mod => "mod",
Self::Lte => "<=", Self::Mul => "*",
Self::Lt => "<", Self::MulWrapped => "mul_wrapped",
Self::Mod => "mod", Self::Nand => "NAND",
Self::Mul => "*", Self::Neq => "!=",
Self::MulWrapped => "mul_wrapped", Self::Nor => "NOR",
Self::Nand => "NAND", Self::Or => "||",
Self::Neq => "!=", Self::BitwiseOr => "|",
Self::Nor => "NOR", Self::Pow => "**",
Self::Or => "||", Self::PowWrapped => "pow_wrapped",
Self::BitwiseOr => "|", Self::Rem => "%",
Self::Pow => "**", Self::RemWrapped => "rem_wrapped",
Self::PowWrapped => "pow_wrapped", Self::Shl => "<<",
Self::Rem => "%", Self::ShlWrapped => "shl_wrapped",
Self::RemWrapped => "rem_wrapped", Self::Shr => ">>",
Self::Shl => "<<", Self::ShrWrapped => "shr_wrapped",
Self::ShlWrapped => "shl_wrapped", Self::Sub => "-",
Self::Shr => ">>", Self::SubWrapped => "sub_wrapped",
Self::ShrWrapped => "shr_wrapped", Self::Xor => "^",
Self::Sub => "-", })
Self::SubWrapped => "sub_wrapped",
Self::Xor => "^",
}
)
} }
} }

View File

@ -82,15 +82,7 @@ impl StructExpression {
impl fmt::Display for StructExpression { impl fmt::Display for StructExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "{{{}}}", self.members.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", "))
f,
"{{{}}}",
self.members
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(", ")
)
} }
} }

View File

@ -30,15 +30,7 @@ pub struct TupleExpression {
impl fmt::Display for TupleExpression { impl fmt::Display for TupleExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "({})", self.elements.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
f,
"({})",
self.elements
.iter()
.map(|x| x.to_string())
.collect::<Vec<_>>()
.join(",")
)
} }
} }

View File

@ -41,11 +41,7 @@ impl External {
impl fmt::Display for External { impl fmt::Display for External {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "{}: {}.leo/{}.record", self.identifier, self.program_name, self.record)
f,
"{}: {}.leo/{}.record",
self.identifier, self.program_name, self.record
)
} }
} }

View File

@ -47,14 +47,7 @@ impl Finalize {
_ => Type::Tuple(Tuple(output.iter().map(|output| output.type_()).collect())), _ => Type::Tuple(Tuple(output.iter().map(|output| output.type_()).collect())),
}; };
Self { Self { identifier, input, output, output_type, block, span }
identifier,
input,
output,
output_type,
block,
span,
}
} }
} }
@ -64,16 +57,9 @@ impl fmt::Display for Finalize {
let returns = match self.output.len() { let returns = match self.output.len() {
0 => "()".to_string(), 0 => "()".to_string(),
1 => self.output[0].to_string(), 1 => self.output[0].to_string(),
_ => format!( _ => format!("({})", self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")),
"({})",
self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
),
}; };
write!( write!(f, " finalize {}({parameters}) -> {returns} {}", self.identifier, self.block)
f,
" finalize {}({parameters}) -> {returns} {}",
self.identifier, self.block
)
} }
} }

View File

@ -97,18 +97,9 @@ impl Function {
_ => Type::Tuple(Tuple(output.iter().map(|output| get_output_type(output)).collect())), _ => Type::Tuple(Tuple(output.iter().map(|output| get_output_type(output)).collect())),
}; };
Function { Function { annotations, variant, identifier, input, output, output_type, block, finalize, span }
annotations,
variant,
identifier,
input,
output,
output_type,
block,
finalize,
span,
}
} }
/// Returns function name. /// Returns function name.
pub fn name(&self) -> Symbol { pub fn name(&self) -> Symbol {
self.identifier.name self.identifier.name

View File

@ -31,6 +31,7 @@ pub enum InputValue {
impl TryFrom<(Type, Expression)> for InputValue { impl TryFrom<(Type, Expression)> for InputValue {
type Error = LeoError; type Error = LeoError;
fn try_from(value: (Type, Expression)) -> Result<Self> { fn try_from(value: (Type, Expression)) -> Result<Self> {
Ok(match value { Ok(match value {
(type_, Expression::Literal(lit)) => match (type_, lit) { (type_, Expression::Literal(lit)) => match (type_, lit) {

View File

@ -24,6 +24,7 @@ pub struct ProgramInput {
impl TryFrom<InputAst> for ProgramInput { impl TryFrom<InputAst> for ProgramInput {
type Error = LeoError; type Error = LeoError;
fn try_from(input: InputAst) -> Result<Self> { fn try_from(input: InputAst) -> Result<Self> {
let mut main = IndexMap::new(); let mut main = IndexMap::new();
@ -34,10 +35,7 @@ impl TryFrom<InputAst> for ProgramInput {
}; };
for definition in section.definitions { for definition in section.definitions {
target.insert( target.insert(definition.name.name, InputValue::try_from((definition.type_, definition.value))?);
definition.name.name,
InputValue::try_from((definition.type_, definition.value))?,
);
} }
} }

View File

@ -157,10 +157,7 @@ impl AsRef<Program> for Ast {
pub(crate) fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value { pub(crate) fn remove_key_from_json(value: serde_json::Value, key: &str) -> serde_json::Value {
match value { match value {
serde_json::Value::Object(map) => serde_json::Value::Object( serde_json::Value::Object(map) => serde_json::Value::Object(
map.into_iter() map.into_iter().filter(|(k, _)| k != key).map(|(k, v)| (k, remove_key_from_json(v, key))).collect(),
.filter(|(k, _)| k != key)
.map(|(k, v)| (k, remove_key_from_json(v, key)))
.collect(),
), ),
serde_json::Value::Array(values) => { serde_json::Value::Array(values) => {
serde_json::Value::Array(values.into_iter().map(|v| remove_key_from_json(v, key)).collect()) serde_json::Value::Array(values.into_iter().map(|v| remove_key_from_json(v, key)).collect())

View File

@ -36,11 +36,7 @@ pub struct Mapping {
impl fmt::Display for Mapping { impl fmt::Display for Mapping {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "mapping {}: {} => {}", self.identifier, self.key_type, self.value_type)
f,
"mapping {}: {} => {}",
self.identifier, self.key_type, self.value_type
)
} }
} }

View File

@ -47,11 +47,7 @@ pub trait ExpressionReconstructor {
AccessExpression::AssociatedFunction(AssociatedFunction { AccessExpression::AssociatedFunction(AssociatedFunction {
ty: function.ty, ty: function.ty,
name: function.name, name: function.name,
args: function args: function.args.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
.args
.into_iter()
.map(|arg| self.reconstruct_expression(arg).0)
.collect(),
span: function.span, span: function.span,
}) })
} }
@ -87,11 +83,7 @@ pub trait ExpressionReconstructor {
( (
Expression::Call(CallExpression { Expression::Call(CallExpression {
function: Box::new(self.reconstruct_expression(*input.function).0), function: Box::new(self.reconstruct_expression(*input.function).0),
arguments: input arguments: input.arguments.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
.arguments
.into_iter()
.map(|arg| self.reconstruct_expression(arg).0)
.collect(),
external: input.external, external: input.external,
span: input.span, span: input.span,
}), }),
@ -130,11 +122,7 @@ pub trait ExpressionReconstructor {
fn reconstruct_tuple(&mut self, input: TupleExpression) -> (Expression, Self::AdditionalOutput) { fn reconstruct_tuple(&mut self, input: TupleExpression) -> (Expression, Self::AdditionalOutput) {
( (
Expression::Tuple(TupleExpression { Expression::Tuple(TupleExpression {
elements: input elements: input.elements.into_iter().map(|element| self.reconstruct_expression(element).0).collect(),
.elements
.into_iter()
.map(|element| self.reconstruct_expression(element).0)
.collect(),
span: input.span, span: input.span,
}), }),
Default::default(), Default::default(),
@ -212,11 +200,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) { fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
( (
Block { Block {
statements: input statements: input.statements.into_iter().map(|s| self.reconstruct_statement(s).0).collect(),
.statements
.into_iter()
.map(|s| self.reconstruct_statement(s).0)
.collect(),
span: input.span, span: input.span,
}, },
Default::default(), Default::default(),
@ -326,10 +310,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
Statement::Return(ReturnStatement { Statement::Return(ReturnStatement {
expression: self.reconstruct_expression(input.expression).0, expression: self.reconstruct_expression(input.expression).0,
finalize_arguments: input.finalize_arguments.map(|arguments| { finalize_arguments: input.finalize_arguments.map(|arguments| {
arguments arguments.into_iter().map(|argument| self.reconstruct_expression(argument).0).collect()
.into_iter()
.map(|argument| self.reconstruct_expression(argument).0)
.collect()
}), }),
span: input.span, span: input.span,
}), }),
@ -358,21 +339,9 @@ pub trait ProgramReconstructor: StatementReconstructor {
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope { fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
ProgramScope { ProgramScope {
program_id: input.program_id, program_id: input.program_id,
structs: input structs: input.structs.into_iter().map(|(i, c)| (i, self.reconstruct_struct(c))).collect(),
.structs mappings: input.mappings.into_iter().map(|(id, mapping)| (id, self.reconstruct_mapping(mapping))).collect(),
.into_iter() functions: input.functions.into_iter().map(|(i, f)| (i, self.reconstruct_function(f))).collect(),
.map(|(i, c)| (i, self.reconstruct_struct(c)))
.collect(),
mappings: input
.mappings
.into_iter()
.map(|(id, mapping)| (id, self.reconstruct_mapping(mapping)))
.collect(),
functions: input
.functions
.into_iter()
.map(|(i, f)| (i, self.reconstruct_function(f)))
.collect(),
span: input.span, span: input.span,
} }
} }

View File

@ -214,10 +214,7 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
fn visit_program(&mut self, input: &'a Program) { fn visit_program(&mut self, input: &'a Program) {
input.imports.values().for_each(|import| self.visit_import(&import.0)); input.imports.values().for_each(|import| self.visit_import(&import.0));
input input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
.program_scopes
.values()
.for_each(|scope| self.visit_program_scope(scope));
} }
fn visit_program_scope(&mut self, input: &'a ProgramScope) { fn visit_program_scope(&mut self, input: &'a ProgramScope) {
@ -225,10 +222,7 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
input.mappings.values().for_each(|mapping| self.visit_mapping(mapping)); input.mappings.values().for_each(|mapping| self.visit_mapping(mapping));
input input.functions.values().for_each(|function| self.visit_function(function));
.functions
.values()
.for_each(|function| self.visit_function(function));
} }
fn visit_import(&mut self, input: &'a Program) { fn visit_import(&mut self, input: &'a Program) {

View File

@ -53,9 +53,6 @@ impl fmt::Display for Program {
impl Default for Program { impl Default for Program {
/// Constructs an empty program node. /// Constructs an empty program node.
fn default() -> Self { fn default() -> Self {
Self { Self { imports: IndexMap::new(), program_scopes: IndexMap::new() }
imports: IndexMap::new(),
program_scopes: IndexMap::new(),
}
} }
} }

View File

@ -17,8 +17,7 @@
use crate::Identifier; use crate::Identifier;
use core::fmt; use core::fmt;
use serde::de::Visitor; use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::collections::BTreeMap; use std::collections::BTreeMap;
/// An identifier for a program that is eventually deployed to the network. /// An identifier for a program that is eventually deployed to the network.

View File

@ -35,9 +35,7 @@ impl fmt::Display for Block {
if self.statements.is_empty() { if self.statements.is_empty() {
writeln!(f, "\t")?; writeln!(f, "\t")?;
} else { } else {
self.statements self.statements.iter().try_for_each(|statement| writeln!(f, "\t{statement}"))?;
.iter()
.try_for_each(|statement| writeln!(f, "\t{statement}"))?;
} }
write!(f, "}}") write!(f, "}}")
} }

View File

@ -19,8 +19,7 @@ use crate::{Block, Expression, Identifier, Node, Type, Value};
use leo_span::Span; use leo_span::Span;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::cell::RefCell; use std::{cell::RefCell, fmt};
use std::fmt;
/// A bounded `for` loop statement `for variable in start .. =? stop block`. /// A bounded `for` loop statement `for variable in start .. =? stop block`.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)] #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
@ -51,11 +50,7 @@ pub struct IterationStatement {
impl fmt::Display for IterationStatement { impl fmt::Display for IterationStatement {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let eq = if self.inclusive { "=" } else { "" }; let eq = if self.inclusive { "=" } else { "" };
write!( write!(f, "for {} in {}..{eq}{} {}", self.variable, self.start, self.stop, self.block)
f,
"for {} in {}..{eq}{} {}",
self.variable, self.start, self.stop, self.block
)
} }
} }

View File

@ -84,10 +84,7 @@ pub enum Statement {
impl Statement { impl Statement {
/// Returns a dummy statement made from an empty block `{}`. /// Returns a dummy statement made from an empty block `{}`.
pub fn dummy(span: Span) -> Self { pub fn dummy(span: Span) -> Self {
Self::Block(Block { Self::Block(Block { statements: Vec::new(), span })
statements: Vec::new(),
span,
})
} }
} }

View File

@ -35,10 +35,6 @@ impl Deref for Tuple {
impl fmt::Display for Tuple { impl fmt::Display for Tuple {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "({})", self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
f,
"({})",
self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
)
} }
} }

View File

@ -70,10 +70,9 @@ impl Type {
(Type::Mapping(left), Type::Mapping(right)) => { (Type::Mapping(left), Type::Mapping(right)) => {
left.key.eq_flat(&right.key) && left.value.eq_flat(&right.value) left.key.eq_flat(&right.key) && left.value.eq_flat(&right.value)
} }
(Type::Tuple(left), Type::Tuple(right)) if left.len() == right.len() => left (Type::Tuple(left), Type::Tuple(right)) if left.len() == right.len() => {
.iter() left.iter().zip_eq(right.iter()).all(|(left_type, right_type)| left_type.eq_flat(right_type))
.zip_eq(right.iter()) }
.all(|(left_type, right_type)| left_type.eq_flat(right_type)),
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right), (Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
_ => false, _ => false,
} }

View File

@ -201,26 +201,6 @@ pub enum Value {
} }
impl Value { impl Value {
// TODO: This is temporary since the currently unused code is used in constant folding.
#[allow(dead_code)]
pub(crate) fn is_supported_const_fold_type(&self) -> bool {
use Value::*;
matches!(
self,
Boolean(_, _)
| I8(_, _)
| I16(_, _)
| I32(_, _)
| I64(_, _)
| I128(_, _)
| U8(_, _)
| U16(_, _)
| U32(_, _)
| U64(_, _)
| U128(_, _)
)
}
implement_const_unary!( implement_const_unary!(
@overflowing @overflowing
name: abs, name: abs,
@ -720,6 +700,26 @@ impl Value {
[U128, [U128], U128, u128, u128] [U128, [U128], U128, u128, u128]
] ]
); );
// TODO: This is temporary since the currently unused code is used in constant folding.
#[allow(dead_code)]
pub(crate) fn is_supported_const_fold_type(&self) -> bool {
use Value::*;
matches!(
self,
Boolean(_, _)
| I8(_, _)
| I16(_, _)
| I32(_, _)
| I64(_, _)
| I128(_, _)
| U8(_, _)
| U16(_, _)
| U32(_, _)
| U64(_, _)
| U128(_, _)
)
}
} }
impl Display for Value { impl Display for Value {

View File

@ -19,16 +19,13 @@
//! The [`Compiler`] type compiles Leo programs into R1CS circuits. //! The [`Compiler`] type compiles Leo programs into R1CS circuits.
use leo_ast::Program; use leo_ast::Program;
pub use leo_ast::{Ast, InputAst}; pub use leo_ast::{Ast, InputAst};
use leo_errors::emitter::Handler; use leo_errors::{emitter::Handler, CompilerError, Result};
use leo_errors::{CompilerError, Result};
pub use leo_passes::SymbolTable; pub use leo_passes::SymbolTable;
use leo_passes::*; use leo_passes::*;
use leo_span::source_map::FileName; use leo_span::{source_map::FileName, symbol::with_session_globals};
use leo_span::symbol::with_session_globals;
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use std::fs; use std::{fs, path::PathBuf};
use std::path::PathBuf;
use crate::CompilerOptions; use crate::CompilerOptions;
@ -273,10 +270,7 @@ impl<'a> Compiler<'a> {
fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> { fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> {
// Remove `Span`s if they are not enabled. // Remove `Span`s if they are not enabled.
if self.compiler_options.spans_enabled { if self.compiler_options.spans_enabled {
self.ast.to_json_file( self.ast.to_json_file(self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name))?;
self.output_directory.clone(),
&format!("{}.{file_suffix}", self.program_name),
)?;
} else { } else {
self.ast.to_json_file_without_keys( self.ast.to_json_file_without_keys(
self.output_directory.clone(), self.output_directory.clone(),

View File

@ -29,8 +29,7 @@ use snarkvm::prelude::*;
use crate::utilities::{get_cwd_option, hash_asts, hash_content, setup_build_directory}; use crate::utilities::{get_cwd_option, hash_asts, hash_content, setup_build_directory};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::Value; use serde_yaml::Value;
use std::rc::Rc; use std::{fs, path::Path, rc::Rc};
use std::{fs, path::Path};
struct CompileNamespace; struct CompileNamespace;

View File

@ -15,8 +15,16 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
mod utilities; mod utilities;
use utilities::{buffer_if_err, compile_and_process, parse_program, BufferEmitter}; use utilities::{
use utilities::{get_cwd_option, setup_build_directory, Aleo, Network}; buffer_if_err,
compile_and_process,
get_cwd_option,
parse_program,
setup_build_directory,
Aleo,
BufferEmitter,
Network,
};
use crate::utilities::{hash_asts, hash_content}; use crate::utilities::{hash_asts, hash_content};
@ -27,15 +35,13 @@ use leo_test_framework::{
Test, Test,
}; };
use snarkvm::console; use snarkvm::{console, prelude::*};
use snarkvm::prelude::*;
use leo_test_framework::test::TestExpectationMode; use leo_test_framework::test::TestExpectationMode;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_yaml::Value; use serde_yaml::Value;
use std::collections::BTreeMap; use std::{collections::BTreeMap, fs, path::Path, rc::Rc};
use std::{fs, path::Path, rc::Rc};
// TODO: Evaluate namespace. // TODO: Evaluate namespace.
struct ExecuteNamespace; struct ExecuteNamespace;
@ -69,10 +75,7 @@ struct ExecuteOutput {
fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Value, ()> { fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Value, ()> {
// Check that config expectation is always pass. // Check that config expectation is always pass.
if test.config.expectation != TestExpectationMode::Pass { if test.config.expectation != TestExpectationMode::Pass {
buffer_if_err( buffer_if_err(err_buf, Err("Test expectation must be `Pass` for `Execute` tests.".to_string()))?;
err_buf,
Err("Test expectation must be `Pass` for `Execute` tests.".to_string()),
)?;
} }
// Check for CWD option: // Check for CWD option:
@ -86,13 +89,8 @@ fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Va
let bytecode = handler.extend_if_error(compile_and_process(&mut parsed))?; let bytecode = handler.extend_if_error(compile_and_process(&mut parsed))?;
// Extract the cases from the test config. // Extract the cases from the test config.
let all_cases = test let all_cases =
.config test.config.extra.get("cases").expect("An `Execute` config must have a `cases` field.").as_mapping().unwrap();
.extra
.get("cases")
.expect("An `Execute` config must have a `cases` field.")
.as_mapping()
.unwrap();
// Initialize a map for the expected results. // Initialize a map for the expected results.
let mut results = BTreeMap::new(); let mut results = BTreeMap::new();

View File

@ -17,7 +17,8 @@
use leo_compiler::{Compiler, CompilerOptions}; use leo_compiler::{Compiler, CompilerOptions};
use leo_errors::{ use leo_errors::{
emitter::{Buffer, Emitter, Handler}, emitter::{Buffer, Emitter, Handler},
LeoError, LeoWarning, LeoError,
LeoWarning,
}; };
use leo_passes::{CodeGenerator, Pass}; use leo_passes::{CodeGenerator, Pass};
use leo_span::source_map::FileName; use leo_span::source_map::FileName;
@ -25,12 +26,11 @@ use leo_test_framework::Test;
use snarkvm::prelude::*; use snarkvm::prelude::*;
use snarkvm::file::Manifest; use snarkvm::{file::Manifest, package::Package};
use snarkvm::package::Package;
use std::fs::File;
use std::{ use std::{
cell::RefCell, cell::RefCell,
fs, fs,
fs::File,
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc, rc::Rc,
}; };
@ -152,10 +152,7 @@ impl Display for LeoOrString {
/// A buffer used to emit errors into. /// A buffer used to emit errors into.
#[derive(Clone)] #[derive(Clone)]
pub struct BufferEmitter( pub struct BufferEmitter(pub Rc<RefCell<Buffer<LeoOrString>>>, pub Rc<RefCell<Buffer<LeoWarning>>>);
pub Rc<RefCell<Buffer<LeoOrString>>>,
pub Rc<RefCell<Buffer<LeoWarning>>>,
);
impl Emitter for BufferEmitter { impl Emitter for BufferEmitter {
fn emit_err(&mut self, err: LeoError) { fn emit_err(&mut self, err: LeoError) {
@ -181,9 +178,7 @@ pub fn buffer_if_err<T>(buf: &BufferEmitter, res: Result<T, String>) -> Result<T
} }
pub fn temp_dir() -> PathBuf { pub fn temp_dir() -> PathBuf {
tempfile::tempdir() tempfile::tempdir().expect("Failed to open temporary directory").into_path()
.expect("Failed to open temporary directory")
.into_path()
} }
pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> { pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {

View File

@ -26,10 +26,7 @@ use std::{
}; };
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
#[structopt( #[structopt(name = "input parser", about = "Parse an Input file and save its JSON representation")]
name = "input parser",
about = "Parse an Input file and save its JSON representation"
)]
struct Opt { struct Opt {
/// Path to the input file. /// Path to the input file.
#[structopt(parse(from_os_str))] #[structopt(parse(from_os_str))]
@ -47,10 +44,7 @@ struct Opt {
fn main() -> Result<(), String> { fn main() -> Result<(), String> {
let opt = Opt::parse(); let opt = Opt::parse();
let input_tree = create_session_if_not_set_then(|s| { let input_tree = create_session_if_not_set_then(|s| {
let input_string = s let input_string = s.source_map.load_file(&opt.input_path).expect("failed to open an input file");
.source_map
.load_file(&opt.input_path)
.expect("failed to open an input file");
Handler::with(|handler| { Handler::with(|handler| {
let input = leo_parser::parse_program_inputs(handler, &input_string.src, input_string.start_pos)?; let input = leo_parser::parse_program_inputs(handler, &input_string.src, input_string.start_pos)?;
@ -64,11 +58,7 @@ fn main() -> Result<(), String> {
} }
let out_path = if let Some(out_dir) = opt.out_dir_path { let out_path = if let Some(out_dir) = opt.out_dir_path {
format!( format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
"{}/{}.json",
out_dir.as_path().display(),
opt.input_path.file_stem().unwrap().to_str().unwrap()
)
} else { } else {
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap()) format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
}; };

View File

@ -62,11 +62,7 @@ fn main() -> Result<(), String> {
} }
let out_path = if let Some(out_dir) = opt.out_dir_path { let out_path = if let Some(out_dir) = opt.out_dir_path {
format!( format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
"{}/{}.json",
out_dir.as_path().display(),
opt.input_path.file_stem().unwrap().to_str().unwrap()
)
} else { } else {
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap()) format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
}; };

View File

@ -32,8 +32,7 @@ pub mod parser;
pub use parser::*; pub use parser::*;
use leo_ast::{input::InputData, Ast, ProgramInput}; use leo_ast::{input::InputData, Ast, ProgramInput};
use leo_errors::emitter::Handler; use leo_errors::{emitter::Handler, Result};
use leo_errors::Result;
#[cfg(test)] #[cfg(test)]
mod test; mod test;

View File

@ -17,12 +17,10 @@
use crate::{tokenizer::*, Token}; use crate::{tokenizer::*, Token};
use leo_ast::*; use leo_ast::*;
use leo_errors::emitter::Handler; use leo_errors::{emitter::Handler, ParserError, ParserWarning, Result};
use leo_errors::{ParserError, ParserWarning, Result};
use leo_span::{Span, Symbol}; use leo_span::{Span, Symbol};
use std::fmt::Display; use std::{fmt::Display, mem};
use std::mem;
/// Stores a program in tokenized format plus additional context. /// Stores a program in tokenized format plus additional context.
/// May be converted into a [`Program`] AST by parsing all tokens. /// May be converted into a [`Program`] AST by parsing all tokens.
@ -44,10 +42,7 @@ pub(crate) struct ParserContext<'a> {
} }
/// Dummy span used to appease borrow checker. /// Dummy span used to appease borrow checker.
const DUMMY_EOF: SpannedToken = SpannedToken { const DUMMY_EOF: SpannedToken = SpannedToken { token: Token::Eof, span: Span::dummy() };
token: Token::Eof,
span: Span::dummy(),
};
impl<'a> ParserContext<'a> { impl<'a> ParserContext<'a> {
/// Returns a new [`ParserContext`] type given a vector of tokens. /// Returns a new [`ParserContext`] type given a vector of tokens.
@ -81,10 +76,7 @@ impl<'a> ParserContext<'a> {
} }
// Extract next token, or `Eof` if there was none. // Extract next token, or `Eof` if there was none.
let next_token = self.tokens.pop().unwrap_or(SpannedToken { let next_token = self.tokens.pop().unwrap_or(SpannedToken { token: Token::Eof, span: self.token.span });
token: Token::Eof,
span: self.token.span,
});
// Set the new token. // Set the new token.
self.prev_token = mem::replace(&mut self.token, next_token); self.prev_token = mem::replace(&mut self.token, next_token);
@ -183,11 +175,7 @@ impl<'a> ParserContext<'a> {
/// Eats the expected `token`, or errors. /// Eats the expected `token`, or errors.
pub(super) fn expect(&mut self, token: &Token) -> Result<Span> { pub(super) fn expect(&mut self, token: &Token) -> Result<Span> {
if self.eat(token) { if self.eat(token) { Ok(self.prev_token.span) } else { self.unexpected(token) }
Ok(self.prev_token.span)
} else {
self.unexpected(token)
}
} }
/// Eats one of the expected `tokens`, or errors. /// Eats one of the expected `tokens`, or errors.

View File

@ -215,10 +215,7 @@ impl ParserContext<'_> {
/// ///
/// Otherwise, tries to parse the next token using [`parse_exponential_expression`]. /// Otherwise, tries to parse the next token using [`parse_exponential_expression`].
fn parse_multiplicative_expression(&mut self) -> Result<Expression> { fn parse_multiplicative_expression(&mut self) -> Result<Expression> {
self.parse_bin_expr( self.parse_bin_expr(&[Token::Mul, Token::Div, Token::Rem], Self::parse_exponential_expression)
&[Token::Mul, Token::Div, Token::Rem],
Self::parse_exponential_expression,
)
} }
/// Returns an [`Expression`] AST node if the next tokens represent a /// Returns an [`Expression`] AST node if the next tokens represent a
@ -266,11 +263,7 @@ impl ParserContext<'_> {
Expression::Literal(Literal::Integer(integer_type, format!("-{string}"), op_span + span)) Expression::Literal(Literal::Integer(integer_type, format!("-{string}"), op_span + span))
} }
// Otherwise, produce a unary expression. // Otherwise, produce a unary expression.
_ => Expression::Unary(UnaryExpression { _ => Expression::Unary(UnaryExpression { span: op_span + inner.span(), op, receiver: Box::new(inner) }),
span: op_span + inner.span(),
op,
receiver: Box::new(inner),
}),
}; };
} }
Ok(inner) Ok(inner)
@ -285,11 +278,7 @@ impl ParserContext<'_> {
if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) { if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
// Found an unary operator and the argument list is empty. // Found an unary operator and the argument list is empty.
Ok(Expression::Unary(UnaryExpression { Ok(Expression::Unary(UnaryExpression { span, op, receiver: Box::new(receiver) }))
span,
op,
receiver: Box::new(receiver),
}))
} else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) { } else if let (1, Some(op)) = (args.len(), BinaryOperation::from_symbol(method.name)) {
// Found a binary operator and the argument list contains a single argument. // Found a binary operator and the argument list contains a single argument.
Ok(Expression::Binary(BinaryExpression { Ok(Expression::Binary(BinaryExpression {
@ -359,11 +348,8 @@ impl ParserContext<'_> {
if self.check_int() { if self.check_int() {
// Eat a tuple member access. // Eat a tuple member access.
let (index, span) = self.eat_integer()?; let (index, span) = self.eat_integer()?;
expr = Expression::Access(AccessExpression::Tuple(TupleAccess { expr =
tuple: Box::new(expr), Expression::Access(AccessExpression::Tuple(TupleAccess { tuple: Box::new(expr), index, span }))
index,
span,
}))
} else if self.eat(&Token::Leo) { } else if self.eat(&Token::Leo) {
// Eat an external function call. // Eat an external function call.
self.eat(&Token::Div); // todo: Make `/` a more general token. self.eat(&Token::Div); // todo: Make `/` a more general token.
@ -484,11 +470,7 @@ impl ParserContext<'_> {
let end_span = check_ahead(dist, &Token::Group)?; let end_span = check_ahead(dist, &Token::Group)?;
dist += 1; // Standing at `)` so advance one for 'group'. dist += 1; // Standing at `)` so advance one for 'group'.
let gt = GroupTuple { let gt = GroupTuple { span: start_span + &end_span, x: first_gc, y: second_gc };
span: start_span + &end_span,
x: first_gc,
y: second_gc,
};
// Eat everything so that this isn't just peeking. // Eat everything so that this isn't just peeking.
for _ in 0..dist { for _ in 0..dist {
@ -525,15 +507,10 @@ impl ParserContext<'_> {
/// struct initialization expression. /// struct initialization expression.
/// let foo = Foo { x: 1u8 }; /// let foo = Foo { x: 1u8 };
pub fn parse_struct_init_expression(&mut self, identifier: Identifier) -> Result<Expression> { pub fn parse_struct_init_expression(&mut self, identifier: Identifier) -> Result<Expression> {
let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| { let (members, _, end) =
p.parse_struct_member().map(Some) self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_struct_member().map(Some))?;
})?;
Ok(Expression::Struct(StructExpression { Ok(Expression::Struct(StructExpression { span: identifier.span + end, name: identifier, members }))
span: identifier.span + end,
name: identifier,
members,
}))
} }
/// Returns an [`Expression`] AST node if the next token is a primary expression: /// Returns an [`Expression`] AST node if the next token is a primary expression:
@ -600,14 +577,10 @@ impl ParserContext<'_> {
Expression::Identifier(ident) Expression::Identifier(ident)
} }
} }
Token::SelfLower => Expression::Identifier(Identifier { Token::SelfLower => Expression::Identifier(Identifier { name: sym::SelfLower, span }),
name: sym::SelfLower, t if crate::type_::TYPE_TOKENS.contains(&t) => {
span, Expression::Identifier(Identifier { name: t.keyword_to_symbol().unwrap(), span })
}), }
t if crate::type_::TYPE_TOKENS.contains(&t) => Expression::Identifier(Identifier {
name: t.keyword_to_symbol().unwrap(),
span,
}),
token => { token => {
return Err(ParserError::unexpected_str(token, "expression", span).into()); return Err(ParserError::unexpected_str(token, "expression", span).into());
} }

View File

@ -17,8 +17,7 @@
use super::*; use super::*;
use crate::parse_ast; use crate::parse_ast;
use leo_errors::{CompilerError, ParserError, Result}; use leo_errors::{CompilerError, ParserError, Result};
use leo_span::source_map::FileName; use leo_span::{source_map::FileName, symbol::with_session_globals};
use leo_span::symbol::with_session_globals;
use std::fs; use std::fs;
@ -57,10 +56,7 @@ impl ParserContext<'_> {
return Err(ParserError::missing_program_scope(self.token.span).into()); return Err(ParserError::missing_program_scope(self.token.span).into());
} }
Ok(Program { Ok(Program { imports, program_scopes })
imports,
program_scopes,
})
} }
fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError { fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError {
@ -162,19 +158,16 @@ impl ParserContext<'_> {
} }
Token::RightCurly => break, Token::RightCurly => break,
_ => { _ => {
return Err(Self::unexpected_item( return Err(Self::unexpected_item(&self.token, &[
&self.token, Token::Struct,
&[ Token::Record,
Token::Struct, Token::Mapping,
Token::Record, Token::At,
Token::Mapping, Token::Function,
Token::At, Token::Transition,
Token::Function, Token::Inline,
Token::Transition, ])
Token::Inline, .into());
],
)
.into())
} }
} }
} }
@ -182,13 +175,7 @@ impl ParserContext<'_> {
// Parse `}`. // Parse `}`.
let end = self.expect(&Token::RightCurly)?; let end = self.expect(&Token::RightCurly)?;
Ok(ProgramScope { Ok(ProgramScope { program_id, functions, structs, mappings, span: start + end })
program_id,
functions,
structs,
mappings,
span: start + end,
})
} }
/// Returns a [`Vec<Member>`] AST node if the next tokens represent a struct member. /// Returns a [`Vec<Member>`] AST node if the next tokens represent a struct member.
@ -236,12 +223,7 @@ impl ParserContext<'_> {
let (identifier, type_, span) = self.parse_typed_ident()?; let (identifier, type_, span) = self.parse_typed_ident()?;
Ok(Member { Ok(Member { mode, identifier, type_, span })
mode,
identifier,
type_,
span,
})
} }
/// Parses a struct or record definition, e.g., `struct Foo { ... }` or `record Foo { ... }`. /// Parses a struct or record definition, e.g., `struct Foo { ... }` or `record Foo { ... }`.
@ -253,15 +235,7 @@ impl ParserContext<'_> {
self.expect(&Token::LeftCurly)?; self.expect(&Token::LeftCurly)?;
let (members, end) = self.parse_struct_members()?; let (members, end) = self.parse_struct_members()?;
Ok(( Ok((struct_name.name, Struct { identifier: struct_name, members, is_record, span: start + end }))
struct_name.name,
Struct {
identifier: struct_name,
members,
is_record,
span: start + end,
},
))
} }
/// Parses a mapping declaration, e.g. `mapping balances: address => u128`. /// Parses a mapping declaration, e.g. `mapping balances: address => u128`.
@ -273,15 +247,7 @@ impl ParserContext<'_> {
self.expect(&Token::BigArrow)?; self.expect(&Token::BigArrow)?;
let (value_type, _) = self.parse_type()?; let (value_type, _) = self.parse_type()?;
let end = self.expect(&Token::Semicolon)?; let end = self.expect(&Token::Semicolon)?;
Ok(( Ok((identifier.name, Mapping { identifier, key_type, value_type, span: start + end }))
identifier.name,
Mapping {
identifier,
key_type,
value_type,
span: start + end,
},
))
} }
// TODO: Return a span associated with the mode. // TODO: Return a span associated with the mode.
@ -332,21 +298,11 @@ impl ParserContext<'_> {
self.eat(&Token::Record); self.eat(&Token::Record);
span = span + self.prev_token.span; span = span + self.prev_token.span;
Ok(functions::Input::External(External { Ok(functions::Input::External(External { identifier: name, program_name: external, record, span }))
identifier: name,
program_name: external,
record,
span,
}))
} else { } else {
let type_ = self.parse_type()?.0; let type_ = self.parse_type()?.0;
Ok(functions::Input::Internal(FunctionInput { Ok(functions::Input::Internal(FunctionInput { identifier: name, mode, type_, span: name.span }))
identifier: name,
mode,
type_,
span: name.span,
}))
} }
} }
@ -389,10 +345,7 @@ impl ParserContext<'_> {
} }
fn peek_is_external(&self) -> bool { fn peek_is_external(&self) -> bool {
matches!( matches!((&self.token.token, self.look_ahead(1, |t| &t.token)), (Token::Identifier(_), Token::Dot))
(&self.token.token, self.look_ahead(1, |t| &t.token)),
(Token::Identifier(_), Token::Dot)
)
} }
/// Returns an [`Annotation`] AST node if the next tokens represent an annotation. /// Returns an [`Annotation`] AST node if the next tokens represent an annotation.
@ -400,10 +353,7 @@ impl ParserContext<'_> {
// Parse the `@` symbol and identifier. // Parse the `@` symbol and identifier.
let start = self.expect(&Token::At)?; let start = self.expect(&Token::At)?;
let identifier = match self.token.token { let identifier = match self.token.token {
Token::Program => Identifier { Token::Program => Identifier { name: sym::program, span: self.expect(&Token::Program)? },
name: sym::program,
span: self.expect(&Token::Program)?,
},
_ => self.expect_identifier()?, _ => self.expect_identifier()?,
}; };
let span = start + identifier.span; let span = start + identifier.span;
@ -490,10 +440,7 @@ impl ParserContext<'_> {
}; };
let span = start + block.span; let span = start + block.span;
Ok(( Ok((name.name, Function::new(annotations, variant, name, inputs, output, block, finalize, span)))
name.name,
Function::new(annotations, variant, name, inputs, output, block, finalize, span),
))
} }
} }

View File

@ -55,11 +55,7 @@ impl ParserContext<'_> {
definitions.push(self.parse_input_definition()?); definitions.push(self.parse_input_definition()?);
} }
Ok(Section { Ok(Section { name: section.name, span: section.span, definitions })
name: section.name,
span: section.span,
definitions,
})
} }
/// Parses a single parameter definition: /// Parses a single parameter definition:
@ -75,12 +71,6 @@ impl ParserContext<'_> {
let value = self.parse_unary_expression()?; let value = self.parse_unary_expression()?;
self.expect(&Token::Semicolon)?; self.expect(&Token::Semicolon)?;
Ok(Definition { Ok(Definition { mode, name, type_, value, span })
mode,
name,
type_,
value,
span,
})
} }
} }

View File

@ -22,8 +22,7 @@
use crate::{tokenizer::*, Token}; use crate::{tokenizer::*, Token};
use leo_ast::*; use leo_ast::*;
use leo_errors::emitter::Handler; use leo_errors::{emitter::Handler, Result};
use leo_errors::Result;
use leo_span::Span; use leo_span::Span;
use indexmap::IndexMap; use indexmap::IndexMap;

View File

@ -133,10 +133,7 @@ impl ParserContext<'_> {
} else { } else {
// Parse the expression as a statement. // Parse the expression as a statement.
let end = self.expect(&Token::Semicolon)?; let end = self.expect(&Token::Semicolon)?;
Ok(Statement::Expression(ExpressionStatement { Ok(Statement::Expression(ExpressionStatement { span: place.span() + end, expression: place }))
span: place.span() + end,
expression: place,
}))
} }
} }
@ -174,11 +171,7 @@ impl ParserContext<'_> {
}; };
let end = self.expect(&Token::Semicolon)?; let end = self.expect(&Token::Semicolon)?;
let span = start + end; let span = start + end;
Ok(ReturnStatement { Ok(ReturnStatement { span, expression, finalize_arguments: finalize_args })
span,
expression,
finalize_arguments: finalize_args,
})
} }
/// Returns a [`DecrementStatement`] AST node if the next tokens represent a decrement statement. /// Returns a [`DecrementStatement`] AST node if the next tokens represent a decrement statement.
@ -194,12 +187,7 @@ impl ParserContext<'_> {
let end = self.expect(&Token::RightParen)?; let end = self.expect(&Token::RightParen)?;
self.expect(&Token::Semicolon)?; self.expect(&Token::Semicolon)?;
let span = start + end; let span = start + end;
Ok(DecrementStatement { Ok(DecrementStatement { mapping, index, amount, span })
mapping,
index,
amount,
span,
})
} }
/// Returns an [`IncrementStatement`] AST node if the next tokens represent an increment statement. /// Returns an [`IncrementStatement`] AST node if the next tokens represent an increment statement.
@ -215,12 +203,7 @@ impl ParserContext<'_> {
let end = self.expect(&Token::RightParen)?; let end = self.expect(&Token::RightParen)?;
self.expect(&Token::Semicolon)?; self.expect(&Token::Semicolon)?;
let span = start + end; let span = start + end;
Ok(IncrementStatement { Ok(IncrementStatement { mapping, index, amount, span })
mapping,
index,
amount,
span,
})
} }
/// Returns a [`ConditionalStatement`] AST node if the next tokens represent a conditional statement. /// Returns a [`ConditionalStatement`] AST node if the next tokens represent a conditional statement.
@ -316,18 +299,13 @@ impl ParserContext<'_> {
)); ));
( (
Default::default(), Default::default(),
ConsoleFunction::Assert(Expression::Err(ErrExpression { ConsoleFunction::Assert(Expression::Err(ErrExpression { span: Default::default() })),
span: Default::default(),
})),
) )
} }
}; };
self.expect(&Token::Semicolon)?; self.expect(&Token::Semicolon)?;
Ok(ConsoleStatement { Ok(ConsoleStatement { span: keyword + span, function })
span: keyword + span,
function,
})
} }
/// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement. /// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement.
@ -349,12 +327,6 @@ impl ParserContext<'_> {
let value = self.parse_expression()?; let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?; self.expect(&Token::Semicolon)?;
Ok(DefinitionStatement { Ok(DefinitionStatement { span: decl_span + value.span(), declaration_type: decl_type, place, type_, value })
span: decl_span + value.span(),
declaration_type: decl_type,
place,
type_,
value,
})
} }
} }

View File

@ -40,13 +40,7 @@ impl Namespace for TokenNamespace {
fn run_test(&self, test: Test) -> Result<Value, String> { fn run_test(&self, test: Test) -> Result<Value, String> {
create_session_if_not_set_then(|s| { create_session_if_not_set_then(|s| {
tokenize(test, s).map(|tokens| { tokenize(test, s).map(|tokens| {
Value::String( Value::String(tokens.into_iter().map(|x| x.to_string()).collect::<Vec<String>>().join(","))
tokens
.into_iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(","),
)
}) })
}) })
} }
@ -71,9 +65,7 @@ fn with_handler<T>(
) -> Result<T, String> { ) -> Result<T, String> {
let (handler, buf) = Handler::new_with_buf(); let (handler, buf) = Handler::new_with_buf();
let mut tokens = ParserContext::new(&handler, tokens); let mut tokens = ParserContext::new(&handler, tokens);
let parsed = handler let parsed = handler.extend_if_error(logic(&mut tokens)).map_err(|_| buf.extract_errs().to_string())?;
.extend_if_error(logic(&mut tokens))
.map_err(|_| buf.extract_errs().to_string())?;
not_fully_consumed(&mut tokens)?; not_fully_consumed(&mut tokens)?;
Ok(parsed) Ok(parsed)
} }
@ -84,9 +76,7 @@ fn tokenize(test: Test, s: &SessionGlobals) -> Result<Vec<SpannedToken>, String>
} }
fn all_are_comments(tokens: &[SpannedToken]) -> bool { fn all_are_comments(tokens: &[SpannedToken]) -> bool {
tokens tokens.iter().all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
.iter()
.all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
} }
fn yaml_or_fail<T: Serialize>(value: T) -> Value { fn yaml_or_fail<T: Serialize>(value: T) -> Value {

View File

@ -196,11 +196,7 @@ impl Token {
// Otherwise, return the `first_token` that matches the one character. // Otherwise, return the `first_token` that matches the one character.
let match_two = |input: &mut Peekable<_>, first_token, second_char, second_token| { let match_two = |input: &mut Peekable<_>, first_token, second_char, second_token| {
input.next(); input.next();
Ok(if input.next_if_eq(&second_char).is_some() { Ok(if input.next_if_eq(&second_char).is_some() { (2, second_token) } else { (1, first_token) })
(2, second_token)
} else {
(1, first_token)
})
}; };
// Returns one token matching one or two characters. // Returns one token matching one or two characters.
@ -281,7 +277,7 @@ impl Token {
Token::And, Token::And,
'=', '=',
Token::AndAssign, Token::AndAssign,
) );
} }
'(' => return match_one(&mut input, Token::LeftParen), '(' => return match_one(&mut input, Token::LeftParen),
')' => return match_one(&mut input, Token::RightParen), ')' => return match_one(&mut input, Token::RightParen),
@ -296,7 +292,7 @@ impl Token {
Token::Pow, Token::Pow,
'=', '=',
Token::PowAssign, Token::PowAssign,
) );
} }
'+' => return match_two(&mut input, Token::Add, '=', Token::AddAssign), '+' => return match_two(&mut input, Token::Add, '=', Token::AddAssign),
',' => return match_one(&mut input, Token::Comma), ',' => return match_one(&mut input, Token::Comma),
@ -350,30 +346,8 @@ impl Token {
'%' => return match_two(&mut input, Token::Rem, '=', Token::RemAssign), '%' => return match_two(&mut input, Token::Rem, '=', Token::RemAssign),
':' => return match_two(&mut input, Token::Colon, ':', Token::DoubleColon), ':' => return match_two(&mut input, Token::Colon, ':', Token::DoubleColon),
';' => return match_one(&mut input, Token::Semicolon), ';' => return match_one(&mut input, Token::Semicolon),
'<' => { '<' => return match_four(&mut input, Token::Lt, '=', Token::LtEq, '<', Token::Shl, '=', Token::ShlAssign),
return match_four( '>' => return match_four(&mut input, Token::Gt, '=', Token::GtEq, '>', Token::Shr, '=', Token::ShrAssign),
&mut input,
Token::Lt,
'=',
Token::LtEq,
'<',
Token::Shl,
'=',
Token::ShlAssign,
)
}
'>' => {
return match_four(
&mut input,
Token::Gt,
'=',
Token::GtEq,
'>',
Token::Shr,
'=',
Token::ShrAssign,
)
}
'=' => return match_three(&mut input, Token::Assign, '=', Token::Eq, '>', Token::BigArrow), '=' => return match_three(&mut input, Token::Assign, '=', Token::Eq, '>', Token::BigArrow),
'[' => return match_one(&mut input, Token::LeftSquare), '[' => return match_one(&mut input, Token::LeftSquare),
']' => return match_one(&mut input, Token::RightSquare), ']' => return match_one(&mut input, Token::RightSquare),
@ -389,7 +363,7 @@ impl Token {
Token::Or, Token::Or,
'=', '=',
Token::OrAssign, Token::OrAssign,
) );
} }
'^' => return match_two(&mut input, Token::BitXor, '=', Token::BitXorAssign), '^' => return match_two(&mut input, Token::BitXor, '=', Token::BitXorAssign),
'@' => return Ok((1, Token::At)), '@' => return Ok((1, Token::At)),
@ -451,12 +425,8 @@ impl Token {
)); ));
} }
Err(ParserError::could_not_lex( Err(ParserError::could_not_lex(input.take_while(|c| *c != ';' && !c.is_whitespace()).collect::<String>())
input .into())
.take_while(|c| *c != ';' && !c.is_whitespace())
.collect::<String>(),
)
.into())
} }
} }
@ -469,10 +439,7 @@ pub struct SpannedToken {
impl SpannedToken { impl SpannedToken {
/// Returns a dummy token at a dummy span. /// Returns a dummy token at a dummy span.
pub const fn dummy() -> Self { pub const fn dummy() -> Self {
Self { Self { token: Token::Question, span: Span::dummy() }
token: Token::Question,
span: Span::dummy(),
}
} }
} }

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::SymbolTable; use crate::{CallGraph, StructGraph, SymbolTable};
use crate::{CallGraph, StructGraph};
use leo_ast::Function; use leo_ast::Function;
use leo_span::Symbol; use leo_span::Symbol;

View File

@ -25,8 +25,7 @@ mod visit_statements;
mod visit_type; mod visit_type;
use crate::SymbolTable; use crate::{CallGraph, Pass, StructGraph, SymbolTable};
use crate::{CallGraph, Pass, StructGraph};
use leo_ast::Ast; use leo_ast::Ast;
use leo_errors::Result; use leo_errors::Result;

View File

@ -16,9 +16,23 @@
use crate::CodeGenerator; use crate::CodeGenerator;
use leo_ast::{ use leo_ast::{
AccessExpression, AssociatedFunction, BinaryExpression, BinaryOperation, CallExpression, ErrExpression, Expression, AccessExpression,
Identifier, Literal, MemberAccess, StructExpression, TernaryExpression, TupleExpression, Type, UnaryExpression, AssociatedFunction,
UnaryOperation, UnitExpression, BinaryExpression,
BinaryOperation,
CallExpression,
ErrExpression,
Expression,
Identifier,
Literal,
MemberAccess,
StructExpression,
TernaryExpression,
TupleExpression,
Type,
UnaryExpression,
UnaryOperation,
UnitExpression,
}; };
use leo_span::sym; use leo_span::sym;
use std::borrow::Borrow; use std::borrow::Borrow;
@ -287,13 +301,7 @@ impl<'a> CodeGenerator<'a> {
Expression::Identifier(identifier) => identifier.name, Expression::Identifier(identifier) => identifier.name,
_ => unreachable!("Parsing guarantees that all `input.function` is always an identifier."), _ => unreachable!("Parsing guarantees that all `input.function` is always an identifier."),
}; };
let return_type = &self let return_type = &self.symbol_table.borrow().functions.get(&function_name).unwrap().output_type;
.symbol_table
.borrow()
.functions
.get(&function_name)
.unwrap()
.output_type;
match return_type { match return_type {
Type::Unit => { Type::Unit => {
call_instruction.push(';'); call_instruction.push(';');

View File

@ -76,13 +76,7 @@ impl<'a> CodeGenerator<'a> {
program_string.push('\n'); program_string.push('\n');
// Visit each mapping in the Leo AST and produce an Aleo mapping declaration. // Visit each mapping in the Leo AST and produce an Aleo mapping declaration.
program_string.push_str( program_string.push_str(&program_scope.mappings.values().map(|mapping| self.visit_mapping(mapping)).join("\n"));
&program_scope
.mappings
.values()
.map(|mapping| self.visit_mapping(mapping))
.join("\n"),
);
// Visit each function in the program scope and produce an Aleo function. // Visit each function in the program scope and produce an Aleo function.
// Note that in the function inlining pass, we reorder the functions such that they are in post-order. // Note that in the function inlining pass, we reorder the functions such that they are in post-order.
@ -118,17 +112,12 @@ impl<'a> CodeGenerator<'a> {
} }
fn visit_struct_or_record(&mut self, struct_: &'a Struct) -> String { fn visit_struct_or_record(&mut self, struct_: &'a Struct) -> String {
if struct_.is_record { if struct_.is_record { self.visit_record(struct_) } else { self.visit_struct(struct_) }
self.visit_record(struct_)
} else {
self.visit_struct(struct_)
}
} }
fn visit_struct(&mut self, struct_: &'a Struct) -> String { fn visit_struct(&mut self, struct_: &'a Struct) -> String {
// Add private symbol to composite types. // Add private symbol to composite types.
self.composite_mapping self.composite_mapping.insert(&struct_.identifier.name, (false, String::from("private"))); // todo: private by default here.
.insert(&struct_.identifier.name, (false, String::from("private"))); // todo: private by default here.
let mut output_string = format!("struct {}:\n", struct_.identifier); // todo: check if this is safe from name conflicts. let mut output_string = format!("struct {}:\n", struct_.identifier); // todo: check if this is safe from name conflicts.
@ -143,8 +132,7 @@ impl<'a> CodeGenerator<'a> {
fn visit_record(&mut self, record: &'a Struct) -> String { fn visit_record(&mut self, record: &'a Struct) -> String {
// Add record symbol to composite types. // Add record symbol to composite types.
let mut output_string = String::from("record"); let mut output_string = String::from("record");
self.composite_mapping self.composite_mapping.insert(&record.identifier.name, (true, output_string.clone()));
.insert(&record.identifier.name, (true, output_string.clone()));
writeln!(output_string, " {}:", record.identifier).expect("failed to write to string"); // todo: check if this is safe from name conflicts. writeln!(output_string, " {}:", record.identifier).expect("failed to write to string"); // todo: check if this is safe from name conflicts.
// Construct and append the record variables. // Construct and append the record variables.
@ -190,8 +178,7 @@ impl<'a> CodeGenerator<'a> {
let type_string = match input { let type_string = match input {
functions::Input::Internal(input) => { functions::Input::Internal(input) => {
self.variable_mapping self.variable_mapping.insert(&input.identifier.name, register_string.clone());
.insert(&input.identifier.name, register_string.clone());
let visibility = match (self.is_transition_function, input.mode) { let visibility = match (self.is_transition_function, input.mode) {
(true, Mode::None) => Mode::Private, (true, Mode::None) => Mode::Private,
_ => input.mode, _ => input.mode,
@ -199,8 +186,7 @@ impl<'a> CodeGenerator<'a> {
self.visit_type_with_visibility(&input.type_, visibility) self.visit_type_with_visibility(&input.type_, visibility)
} }
functions::Input::External(input) => { functions::Input::External(input) => {
self.variable_mapping self.variable_mapping.insert(&input.identifier.name, register_string.clone());
.insert(&input.identifier.name, register_string.clone());
format!("{}.aleo/{}.record", input.program_name, input.record) format!("{}.aleo/{}.record", input.program_name, input.record)
} }
}; };
@ -234,8 +220,7 @@ impl<'a> CodeGenerator<'a> {
// TODO: Dedup code. // TODO: Dedup code.
let type_string = match input { let type_string = match input {
functions::Input::Internal(input) => { functions::Input::Internal(input) => {
self.variable_mapping self.variable_mapping.insert(&input.identifier.name, register_string.clone());
.insert(&input.identifier.name, register_string.clone());
let visibility = match (self.is_transition_function, input.mode) { let visibility = match (self.is_transition_function, input.mode) {
(true, Mode::None) => Mode::Public, (true, Mode::None) => Mode::Public,
@ -244,8 +229,7 @@ impl<'a> CodeGenerator<'a> {
self.visit_type_with_visibility(&input.type_, visibility) self.visit_type_with_visibility(&input.type_, visibility)
} }
functions::Input::External(input) => { functions::Input::External(input) => {
self.variable_mapping self.variable_mapping.insert(&input.program_name.name, register_string.clone());
.insert(&input.program_name.name, register_string.clone());
format!("{}.aleo/{}.record", input.program_name, input.record) format!("{}.aleo/{}.record", input.program_name, input.record)
} }
}; };

View File

@ -17,9 +17,22 @@
use crate::CodeGenerator; use crate::CodeGenerator;
use leo_ast::{ use leo_ast::{
AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DecrementStatement, AssertStatement,
DefinitionStatement, Expression, ExpressionStatement, IncrementStatement, IterationStatement, Mode, Output, AssertVariant,
ReturnStatement, Statement, AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
DecrementStatement,
DefinitionStatement,
Expression,
ExpressionStatement,
IncrementStatement,
IterationStatement,
Mode,
Output,
ReturnStatement,
Statement,
}; };
use itertools::Itertools; use itertools::Itertools;

View File

@ -48,10 +48,7 @@ impl Assigner {
// Create a new variable for the expression. // Create a new variable for the expression.
let name = self.unique_symbol("$var", "$"); let name = self.unique_symbol("$var", "$");
let place = Identifier { let place = Identifier { name, span: Default::default() };
name,
span: Default::default(),
};
(place, self.simple_assign_statement(place, expr)) (place, self.simple_assign_statement(place, expr))
} }

View File

@ -17,8 +17,7 @@
use leo_span::Symbol; use leo_span::Symbol;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use std::fmt::Debug; use std::{fmt::Debug, hash::Hash};
use std::hash::Hash;
/// A struct dependency graph. /// A struct dependency graph.
pub type StructGraph = DiGraph<Symbol>; pub type StructGraph = DiGraph<Symbol>;
@ -54,10 +53,7 @@ pub struct DiGraph<N: Node> {
impl<N: Node> DiGraph<N> { impl<N: Node> DiGraph<N> {
/// Initializes a new `DiGraph` from a vector of source nodes. /// Initializes a new `DiGraph` from a vector of source nodes.
pub fn new(nodes: IndexSet<N>) -> Self { pub fn new(nodes: IndexSet<N>) -> Self {
Self { Self { nodes, edges: IndexMap::new() }
nodes,
edges: IndexMap::new(),
}
} }
/// Adds an edge to the graph. /// Adds an edge to the graph.

View File

@ -30,10 +30,7 @@ pub struct RenameTable {
impl RenameTable { impl RenameTable {
/// Create a new `RenameTable` with the given parent. /// Create a new `RenameTable` with the given parent.
pub(crate) fn new(parent: Option<Box<RenameTable>>) -> Self { pub(crate) fn new(parent: Option<Box<RenameTable>>) -> Self {
Self { Self { parent, mapping: IndexMap::new() }
parent,
mapping: IndexMap::new(),
}
} }
/// Returns the symbols that were renamed in the current scope. /// Returns the symbols that were renamed in the current scope.

View File

@ -146,11 +146,7 @@ impl SymbolTable {
/// Returns true if the variable exists in any parent scope /// Returns true if the variable exists in any parent scope
pub fn variable_in_parent_scope(&self, symbol: Symbol) -> bool { pub fn variable_in_parent_scope(&self, symbol: Symbol) -> bool {
if let Some(parent) = self.parent.as_ref() { if let Some(parent) = self.parent.as_ref() {
if parent.variables.contains_key(&symbol) { if parent.variables.contains_key(&symbol) { true } else { parent.variable_in_parent_scope(symbol) }
true
} else {
parent.variable_in_parent_scope(symbol)
}
} else { } else {
false false
} }

View File

@ -29,9 +29,6 @@ pub struct DeadCodeEliminator {
impl DeadCodeEliminator { impl DeadCodeEliminator {
/// Initializes a new `DeadCodeEliminator`. /// Initializes a new `DeadCodeEliminator`.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self { used_variables: Default::default(), is_necessary: false }
used_variables: Default::default(),
is_necessary: false,
}
} }
} }

View File

@ -17,9 +17,22 @@
use crate::DeadCodeEliminator; use crate::DeadCodeEliminator;
use leo_ast::{ use leo_ast::{
AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DecrementStatement, AssertStatement,
DefinitionStatement, Expression, ExpressionReconstructor, ExpressionStatement, IncrementStatement, AssertVariant,
IterationStatement, ReturnStatement, Statement, StatementReconstructor, AssignStatement,
Block,
ConditionalStatement,
ConsoleStatement,
DecrementStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
ExpressionStatement,
IncrementStatement,
IterationStatement,
ReturnStatement,
Statement,
StatementReconstructor,
}; };
impl StatementReconstructor for DeadCodeEliminator { impl StatementReconstructor for DeadCodeEliminator {
@ -31,14 +44,12 @@ impl StatementReconstructor for DeadCodeEliminator {
let statement = Statement::Assert(AssertStatement { let statement = Statement::Assert(AssertStatement {
variant: match input.variant { variant: match input.variant {
AssertVariant::Assert(expr) => AssertVariant::Assert(self.reconstruct_expression(expr).0), AssertVariant::Assert(expr) => AssertVariant::Assert(self.reconstruct_expression(expr).0),
AssertVariant::AssertEq(left, right) => AssertVariant::AssertEq( AssertVariant::AssertEq(left, right) => {
self.reconstruct_expression(left).0, AssertVariant::AssertEq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
self.reconstruct_expression(right).0, }
), AssertVariant::AssertNeq(left, right) => {
AssertVariant::AssertNeq(left, right) => AssertVariant::AssertNeq( AssertVariant::AssertNeq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
self.reconstruct_expression(left).0, }
self.reconstruct_expression(right).0,
),
}, },
span: input.span, span: input.span,
}); });
@ -95,23 +106,13 @@ impl StatementReconstructor for DeadCodeEliminator {
/// Reconstructs the statements inside a basic block, eliminating any dead code. /// Reconstructs the statements inside a basic block, eliminating any dead code.
fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) { fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
// Reconstruct each of the statements in reverse. // Reconstruct each of the statements in reverse.
let mut statements: Vec<Statement> = block let mut statements: Vec<Statement> =
.statements block.statements.into_iter().rev().map(|statement| self.reconstruct_statement(statement).0).collect();
.into_iter()
.rev()
.map(|statement| self.reconstruct_statement(statement).0)
.collect();
// Reverse the direction of `statements`. // Reverse the direction of `statements`.
statements.reverse(); statements.reverse();
( (Block { statements, span: block.span }, Default::default())
Block {
statements,
span: block.span,
},
Default::default(),
)
} }
/// Flattening removes conditional statements from the program. /// Flattening removes conditional statements from the program.
@ -200,10 +201,7 @@ impl StatementReconstructor for DeadCodeEliminator {
let statement = Statement::Return(ReturnStatement { let statement = Statement::Return(ReturnStatement {
expression: self.reconstruct_expression(input.expression).0, expression: self.reconstruct_expression(input.expression).0,
finalize_arguments: input.finalize_arguments.map(|arguments| { finalize_arguments: input.finalize_arguments.map(|arguments| {
arguments arguments.into_iter().map(|argument| self.reconstruct_expression(argument).0).collect()
.into_iter()
.map(|argument| self.reconstruct_expression(argument).0)
.collect()
}), }),
span: input.span, span: input.span,
}); });

View File

@ -18,8 +18,17 @@ use crate::Flattener;
use itertools::Itertools; use itertools::Itertools;
use leo_ast::{ use leo_ast::{
AccessExpression, AssociatedFunction, Expression, ExpressionReconstructor, Member, MemberAccess, Statement, AccessExpression,
StructExpression, StructVariableInitializer, TernaryExpression, TupleExpression, AssociatedFunction,
Expression,
ExpressionReconstructor,
Member,
MemberAccess,
Statement,
StructExpression,
StructVariableInitializer,
TernaryExpression,
TupleExpression,
}; };
// TODO: Clean up logic. To be done in a follow-up PR (feat/tuples) // TODO: Clean up logic. To be done in a follow-up PR (feat/tuples)
@ -36,11 +45,7 @@ impl ExpressionReconstructor for Flattener<'_> {
Expression::Access(AccessExpression::AssociatedFunction(AssociatedFunction { Expression::Access(AccessExpression::AssociatedFunction(AssociatedFunction {
ty: function.ty, ty: function.ty,
name: function.name, name: function.name,
args: function args: function.args.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
.args
.into_iter()
.map(|arg| self.reconstruct_expression(arg).0)
.collect(),
span: function.span, span: function.span,
})) }))
} }
@ -83,20 +88,10 @@ impl ExpressionReconstructor for Flattener<'_> {
// Accumulate any statements produced. // Accumulate any statements produced.
statements.extend(stmts); statements.extend(stmts);
// Accumulate the struct members. // Accumulate the struct members.
members.push(StructVariableInitializer { members.push(StructVariableInitializer { identifier: member.identifier, expression: Some(expr) });
identifier: member.identifier,
expression: Some(expr),
});
} }
( (Expression::Struct(StructExpression { name: input.name, members, span: input.span }), statements)
Expression::Struct(StructExpression {
name: input.name,
members,
span: input.span,
}),
statements,
)
} }
/// Reconstructs ternary expressions over tuples and structs, accumulating any statements that are generated. /// Reconstructs ternary expressions over tuples and structs, accumulating any statements that are generated.
@ -224,8 +219,7 @@ impl ExpressionReconstructor for Flattener<'_> {
let (identifier, statement) = self.unique_simple_assign_statement(expr); let (identifier, statement) = self.unique_simple_assign_statement(expr);
// Mark the lhs of the assignment as a struct. // Mark the lhs of the assignment as a struct.
self.structs self.structs.insert(identifier.name, first_member_struct.identifier.name);
.insert(identifier.name, first_member_struct.identifier.name);
statements.push(statement); statements.push(statement);
@ -261,14 +255,8 @@ impl ExpressionReconstructor for Flattener<'_> {
(Expression::Identifier(first), Expression::Identifier(second)) (Expression::Identifier(first), Expression::Identifier(second))
if self.structs.contains_key(&first.name) && self.structs.contains_key(&second.name) => if self.structs.contains_key(&first.name) && self.structs.contains_key(&second.name) =>
{ {
let first_struct = self let first_struct = self.symbol_table.lookup_struct(*self.structs.get(&first.name).unwrap()).unwrap();
.symbol_table let second_struct = self.symbol_table.lookup_struct(*self.structs.get(&second.name).unwrap()).unwrap();
.lookup_struct(*self.structs.get(&first.name).unwrap())
.unwrap();
let second_struct = self
.symbol_table
.lookup_struct(*self.structs.get(&second.name).unwrap())
.unwrap();
// Note that type checking guarantees that both expressions have the same same type. This is a sanity check. // Note that type checking guarantees that both expressions have the same same type. This is a sanity check.
assert_eq!(first_struct, second_struct); assert_eq!(first_struct, second_struct);

View File

@ -19,9 +19,27 @@ use itertools::Itertools;
use std::borrow::Borrow; use std::borrow::Borrow;
use leo_ast::{ use leo_ast::{
AssertStatement, AssertVariant, AssignStatement, BinaryExpression, BinaryOperation, Block, ConditionalStatement, AssertStatement,
ConsoleStatement, DefinitionStatement, Expression, ExpressionReconstructor, Identifier, IterationStatement, Node, AssertVariant,
ReturnStatement, Statement, StatementReconstructor, TupleExpression, Type, UnaryExpression, UnaryOperation, AssignStatement,
BinaryExpression,
BinaryOperation,
Block,
ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
Identifier,
IterationStatement,
Node,
ReturnStatement,
Statement,
StatementReconstructor,
TupleExpression,
Type,
UnaryExpression,
UnaryOperation,
}; };
impl StatementReconstructor for Flattener<'_> { impl StatementReconstructor for Flattener<'_> {
@ -135,10 +153,7 @@ impl StatementReconstructor for Flattener<'_> {
{ {
// Lookup the entry in `self.tuples` and add it for the lhs of the assignment. // Lookup the entry in `self.tuples` and add it for the lhs of the assignment.
// Note that the `unwrap` is safe since the match arm checks that the entry exists. // Note that the `unwrap` is safe since the match arm checks that the entry exists.
self.tuples.insert( self.tuples.insert(lhs_identifier.name, self.tuples.get(&rhs_identifier.name).unwrap().clone());
lhs_identifier.name,
self.tuples.get(&rhs_identifier.name).unwrap().clone(),
);
// Note that tuple assignments are removed from the AST. // Note that tuple assignments are removed from the AST.
(Statement::dummy(Default::default()), statements) (Statement::dummy(Default::default()), statements)
} }
@ -205,10 +220,7 @@ impl StatementReconstructor for Flattener<'_> {
} }
(Expression::Identifier(identifier), expression) => { (Expression::Identifier(identifier), expression) => {
self.update_structs(&identifier, &expression); self.update_structs(&identifier, &expression);
( (self.assigner.simple_assign_statement(identifier, expression), statements)
self.assigner.simple_assign_statement(identifier, expression),
statements,
)
} }
// If the lhs is a tuple and the rhs is a function call, then return the reconstructed statement. // If the lhs is a tuple and the rhs is a function call, then return the reconstructed statement.
(Expression::Tuple(tuple), Expression::Call(call)) => { (Expression::Tuple(tuple), Expression::Call(call)) => {
@ -226,22 +238,16 @@ impl StatementReconstructor for Flattener<'_> {
_ => unreachable!("Type checking guarantees that the output type is a tuple."), _ => unreachable!("Type checking guarantees that the output type is a tuple."),
}; };
tuple tuple.elements.iter().zip_eq(output_type.0.iter()).for_each(|(identifier, type_)| {
.elements let identifier = match identifier {
.iter() Expression::Identifier(identifier) => identifier,
.zip_eq(output_type.0.iter()) _ => unreachable!("Type checking guarantees that a tuple element on the lhs is an identifier."),
.for_each(|(identifier, type_)| { };
let identifier = match identifier { // If the output type is a struct, add it to `self.structs`.
Expression::Identifier(identifier) => identifier, if let Type::Identifier(struct_name) = type_ {
_ => unreachable!( self.structs.insert(identifier.name, struct_name.name);
"Type checking guarantees that a tuple element on the lhs is an identifier." }
), });
};
// If the output type is a struct, add it to `self.structs`.
if let Type::Identifier(struct_name) = type_ {
self.structs.insert(identifier.name, struct_name.name);
}
});
( (
Statement::Assign(Box::new(AssignStatement { Statement::Assign(Box::new(AssignStatement {
@ -318,13 +324,7 @@ impl StatementReconstructor for Flattener<'_> {
statements.push(reconstructed_statement); statements.push(reconstructed_statement);
} }
( (Block { span: block.span, statements }, Default::default())
Block {
span: block.span,
statements,
},
Default::default(),
)
} }
/// Flatten a conditional statement into a list of statements. /// Flatten a conditional statement into a list of statements.
@ -390,14 +390,11 @@ impl StatementReconstructor for Flattener<'_> {
Expression::Identifier(identifier) if self.tuples.contains_key(&identifier.name) => { Expression::Identifier(identifier) if self.tuples.contains_key(&identifier.name) => {
// Note that the `unwrap` is safe since the match arm checks that the entry exists in `self.tuples`. // Note that the `unwrap` is safe since the match arm checks that the entry exists in `self.tuples`.
let tuple = self.tuples.get(&identifier.name).unwrap().clone(); let tuple = self.tuples.get(&identifier.name).unwrap().clone();
self.returns.push(( self.returns.push((guard, ReturnStatement {
guard, span: input.span,
ReturnStatement { expression: Expression::Tuple(tuple),
span: input.span, finalize_arguments: input.finalize_arguments,
expression: Expression::Tuple(tuple), }));
finalize_arguments: input.finalize_arguments,
},
));
} }
// Otherwise, add the expression directly. // Otherwise, add the expression directly.
_ => self.returns.push((guard, input)), _ => self.returns.push((guard, input)),

View File

@ -17,8 +17,19 @@
use crate::{Assigner, SymbolTable}; use crate::{Assigner, SymbolTable};
use leo_ast::{ use leo_ast::{
AccessExpression, BinaryExpression, BinaryOperation, Block, Expression, ExpressionReconstructor, Identifier, AccessExpression,
Member, ReturnStatement, Statement, TernaryExpression, TupleExpression, Type, BinaryExpression,
BinaryOperation,
Block,
Expression,
ExpressionReconstructor,
Identifier,
Member,
ReturnStatement,
Statement,
TernaryExpression,
TupleExpression,
Type,
}; };
use leo_span::Symbol; use leo_span::Symbol;
@ -92,10 +103,7 @@ impl<'a> Flattener<'a> {
// Helper to construct and store ternary assignments. e.g `$ret$0 = $var$0 ? $var$1 : $var$2` // Helper to construct and store ternary assignments. e.g `$ret$0 = $var$0 ? $var$1 : $var$2`
let mut construct_ternary_assignment = |guard: Expression, if_true: Expression, if_false: Expression| { let mut construct_ternary_assignment = |guard: Expression, if_true: Expression, if_false: Expression| {
let place = Identifier { let place = Identifier { name: self.assigner.unique_symbol(prefix, "$"), span: Default::default() };
name: self.assigner.unique_symbol(prefix, "$"),
span: Default::default(),
};
let (value, stmts) = self.reconstruct_ternary(TernaryExpression { let (value, stmts) = self.reconstruct_ternary(TernaryExpression {
condition: Box::new(guard), condition: Box::new(guard),
if_true: Box::new(if_true), if_true: Box::new(if_true),
@ -116,14 +124,11 @@ impl<'a> Flattener<'a> {
} }
}; };
let expression = guards let expression = guards.into_iter().rev().fold(last_expression, |acc, (guard, expr)| match guard {
.into_iter() None => unreachable!("All expressions except for the last one must have a guard."),
.rev() // Note that type checking guarantees that all expressions have the same type.
.fold(last_expression, |acc, (guard, expr)| match guard { Some(guard) => construct_ternary_assignment(guard, expr, acc),
None => unreachable!("All expressions except for the last one must have a guard."), });
// Note that type checking guarantees that all expressions have the same type.
Some(guard) => construct_ternary_assignment(guard, expr, acc),
});
(expression, statements) (expression, statements)
} }
@ -136,11 +141,8 @@ impl<'a> Flattener<'a> {
// The inner expression of an access expression is either an identifier or another access expression. // The inner expression of an access expression is either an identifier or another access expression.
let name = self.lookup_struct_symbol(&access.inner).unwrap(); let name = self.lookup_struct_symbol(&access.inner).unwrap();
let struct_ = self.symbol_table.lookup_struct(name).unwrap(); let struct_ = self.symbol_table.lookup_struct(name).unwrap();
let Member { type_, .. } = struct_ let Member { type_, .. } =
.members struct_.members.iter().find(|member| member.name() == access.name.name).unwrap();
.iter()
.find(|member| member.name() == access.name.name)
.unwrap();
match type_ { match type_ {
Type::Identifier(identifier) => Some(identifier.name), Type::Identifier(identifier) => Some(identifier.name),
_ => None, _ => None,

View File

@ -16,8 +16,18 @@
use crate::{Assigner, RenameTable}; use crate::{Assigner, RenameTable};
use leo_ast::{ use leo_ast::{
AssignStatement, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression, ExpressionReconstructor, AssignStatement,
Identifier, IterationStatement, ProgramReconstructor, Statement, StatementReconstructor, StructExpression, ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
Identifier,
IterationStatement,
ProgramReconstructor,
Statement,
StatementReconstructor,
StructExpression,
StructVariableInitializer, StructVariableInitializer,
}; };
use leo_span::Symbol; use leo_span::Symbol;
@ -34,11 +44,7 @@ pub struct AssignmentRenamer {
impl AssignmentRenamer { impl AssignmentRenamer {
/// Initialize a new `AssignmentRenamer`. /// Initialize a new `AssignmentRenamer`.
pub fn new(assigner: Assigner) -> Self { pub fn new(assigner: Assigner) -> Self {
Self { Self { assigner, rename_table: RenameTable::new(None), is_lhs: false }
assigner,
rename_table: RenameTable::new(None),
is_lhs: false,
}
} }
/// Load the internal rename table with a set of entries. /// Load the internal rename table with a set of entries.
@ -56,6 +62,7 @@ impl AssignmentRenamer {
impl ExpressionReconstructor for AssignmentRenamer { impl ExpressionReconstructor for AssignmentRenamer {
type AdditionalOutput = (); type AdditionalOutput = ();
/// Rename the identifier if it is the left-hand side of an assignment, otherwise look up for a new name in the internal rename table. /// Rename the identifier if it is the left-hand side of an assignment, otherwise look up for a new name in the internal rename table.
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) { fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
let name = match self.is_lhs { let name = match self.is_lhs {
@ -72,10 +79,7 @@ impl ExpressionReconstructor for AssignmentRenamer {
false => *self.rename_table.lookup(input.name).unwrap_or(&input.name), false => *self.rename_table.lookup(input.name).unwrap_or(&input.name),
}; };
( (Expression::Identifier(Identifier { name, span: input.span }), Default::default())
Expression::Identifier(Identifier { name, span: input.span }),
Default::default(),
)
} }
/// Rename the variable initializers in the struct expression. /// Rename the variable initializers in the struct expression.
@ -115,14 +119,7 @@ impl StatementReconstructor for AssignmentRenamer {
let place = self.reconstruct_expression(input.place).0; let place = self.reconstruct_expression(input.place).0;
self.is_lhs = false; self.is_lhs = false;
( (Statement::Assign(Box::new(AssignStatement { place, value, span: input.span })), Default::default())
Statement::Assign(Box::new(AssignStatement {
place,
value,
span: input.span,
})),
Default::default(),
)
} }
/// Flattening removes conditional statements from the program. /// Flattening removes conditional statements from the program.

View File

@ -17,8 +17,15 @@
use crate::{FunctionInliner, Replacer}; use crate::{FunctionInliner, Replacer};
use leo_ast::{ use leo_ast::{
CallExpression, Expression, ExpressionReconstructor, Identifier, ReturnStatement, Statement, CallExpression,
StatementReconstructor, UnitExpression, Variant, Expression,
ExpressionReconstructor,
Identifier,
ReturnStatement,
Statement,
StatementReconstructor,
UnitExpression,
Variant,
}; };
use indexmap::IndexMap; use indexmap::IndexMap;
@ -56,12 +63,8 @@ impl ExpressionReconstructor for FunctionInliner<'_> {
.collect::<IndexMap<_, _>>(); .collect::<IndexMap<_, _>>();
// Initializer `self.assignment_renamer` with the function parameters. // Initializer `self.assignment_renamer` with the function parameters.
self.assignment_renamer.load( self.assignment_renamer
callee .load(callee.input.iter().map(|input| (input.identifier().name, input.identifier().name)));
.input
.iter()
.map(|input| (input.identifier().name, input.identifier().name)),
);
// Duplicate the body of the callee and create a unique assignment statement for each assignment in the body. // Duplicate the body of the callee and create a unique assignment statement for each assignment in the body.
// This is necessary to ensure the inlined variables do not conflict with variables in the caller. // This is necessary to ensure the inlined variables do not conflict with variables in the caller.
@ -86,9 +89,7 @@ impl ExpressionReconstructor for FunctionInliner<'_> {
_ => unreachable!("This branch checks that the last statement is a return statement."), _ => unreachable!("This branch checks that the last statement is a return statement."),
} }
} }
_ => Expression::Unit(UnitExpression { _ => Expression::Unit(UnitExpression { span: Default::default() }),
span: Default::default(),
}),
}; };
(result, inlined_statements) (result, inlined_statements)

View File

@ -33,16 +33,12 @@ impl ProgramReconstructor for FunctionInliner<'_> {
// Reconstruct the function. // Reconstruct the function.
let reconstructed_function = self.reconstruct_function(function); let reconstructed_function = self.reconstruct_function(function);
// Add the reconstructed function to the mapping. // Add the reconstructed function to the mapping.
self.reconstructed_functions self.reconstructed_functions.insert(function_name, reconstructed_function);
.insert(function_name, reconstructed_function);
} }
} }
// Check that `input.functions` is empty. // Check that `input.functions` is empty.
// This is a sanity check to ensure that functions in the program scope have been processed. // This is a sanity check to ensure that functions in the program scope have been processed.
assert!( assert!(input.functions.is_empty(), "All functions in the program scope should have been processed.");
input.functions.is_empty(),
"All functions in the program scope should have been processed."
);
// Note that this intentionally clears `self.reconstructed_functions` for the next program scope. // Note that this intentionally clears `self.reconstructed_functions` for the next program scope.
let functions = core::mem::take(&mut self.reconstructed_functions); let functions = core::mem::take(&mut self.reconstructed_functions);

View File

@ -17,8 +17,17 @@
use crate::FunctionInliner; use crate::FunctionInliner;
use leo_ast::{ use leo_ast::{
AssignStatement, Block, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression, AssignStatement,
ExpressionReconstructor, ExpressionStatement, IterationStatement, Statement, StatementReconstructor, Block,
ConditionalStatement,
ConsoleStatement,
DefinitionStatement,
Expression,
ExpressionReconstructor,
ExpressionStatement,
IterationStatement,
Statement,
StatementReconstructor,
}; };
impl StatementReconstructor for FunctionInliner<'_> { impl StatementReconstructor for FunctionInliner<'_> {
@ -29,29 +38,15 @@ impl StatementReconstructor for FunctionInliner<'_> {
match (input.place, value) { match (input.place, value) {
// If the function call produces a tuple, we need to segment the tuple into multiple assignment statements. // If the function call produces a tuple, we need to segment the tuple into multiple assignment statements.
(Expression::Tuple(left), Expression::Tuple(right)) if left.elements.len() == right.elements.len() => { (Expression::Tuple(left), Expression::Tuple(right)) if left.elements.len() == right.elements.len() => {
statements.extend( statements.extend(left.elements.into_iter().zip(right.elements.into_iter()).map(|(lhs, rhs)| {
left.elements Statement::Assign(Box::new(AssignStatement { place: lhs, value: rhs, span: Default::default() }))
.into_iter() }));
.zip(right.elements.into_iter())
.map(|(lhs, rhs)| {
Statement::Assign(Box::new(AssignStatement {
place: lhs,
value: rhs,
span: Default::default(),
}))
}),
);
(Statement::dummy(Default::default()), statements) (Statement::dummy(Default::default()), statements)
} }
(place, value) => ( (place, value) => {
Statement::Assign(Box::new(AssignStatement { (Statement::Assign(Box::new(AssignStatement { place, value, span: input.span })), statements)
place, }
value,
span: input.span,
})),
statements,
),
} }
} }
@ -65,13 +60,7 @@ impl StatementReconstructor for FunctionInliner<'_> {
statements.push(reconstructed_statement); statements.push(reconstructed_statement);
} }
( (Block { span: block.span, statements }, Default::default())
Block {
span: block.span,
statements,
},
Default::default(),
)
} }
/// Flattening removes conditional statements from the program. /// Flattening removes conditional statements from the program.
@ -98,10 +87,7 @@ impl StatementReconstructor for FunctionInliner<'_> {
// If the resulting expression is a unit expression, return a dummy statement. // If the resulting expression is a unit expression, return a dummy statement.
let statement = match expression { let statement = match expression {
Expression::Unit(_) => Statement::dummy(Default::default()), Expression::Unit(_) => Statement::dummy(Default::default()),
_ => Statement::Expression(ExpressionStatement { _ => Statement::Expression(ExpressionStatement { expression, span: input.span }),
expression,
span: input.span,
}),
}; };
(statement, additional_statements) (statement, additional_statements)

View File

@ -15,8 +15,7 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use num_traits::One; use num_traits::One;
use std::fmt::Display; use std::{fmt::Display, ops::Add};
use std::ops::Add;
use leo_ast::Value; use leo_ast::Value;
use leo_errors::LeoError; use leo_errors::LeoError;
@ -47,11 +46,7 @@ pub(crate) struct RangeIterator<I: LoopBound> {
impl<I: LoopBound> RangeIterator<I> { impl<I: LoopBound> RangeIterator<I> {
pub(crate) fn new(start: I, end: I, clusivity: Clusivity) -> Self { pub(crate) fn new(start: I, end: I, clusivity: Clusivity) -> Self {
Self { Self { end, current: Some(start), clusivity }
end,
current: Some(start),
clusivity,
}
} }
} }

View File

@ -22,12 +22,7 @@ impl ProgramReconstructor for Unroller<'_> {
fn reconstruct_function(&mut self, function: Function) -> Function { fn reconstruct_function(&mut self, function: Function) -> Function {
// Lookup function metadata in the symbol table. // Lookup function metadata in the symbol table.
// Note that this unwrap is safe since function metadata is stored in a prior pass. // Note that this unwrap is safe since function metadata is stored in a prior pass.
let function_index = self let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
.symbol_table
.borrow()
.lookup_fn_symbol(function.identifier.name)
.unwrap()
.id;
// Enter the function's scope. // Enter the function's scope.
let previous_function_index = self.enter_scope(function_index); let previous_function_index = self.enter_scope(function_index);

View File

@ -18,8 +18,7 @@ use itertools::Itertools;
use leo_ast::*; use leo_ast::*;
use leo_span::{Span, Symbol}; use leo_span::{Span, Symbol};
use crate::unroller::Unroller; use crate::{unroller::Unroller, VariableSymbol, VariableType};
use crate::{VariableSymbol, VariableType};
impl StatementReconstructor for Unroller<'_> { impl StatementReconstructor for Unroller<'_> {
fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) { fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
@ -29,11 +28,7 @@ impl StatementReconstructor for Unroller<'_> {
let previous_scope_index = self.enter_scope(scope_index); let previous_scope_index = self.enter_scope(scope_index);
let block = Block { let block = Block {
statements: input statements: input.statements.into_iter().map(|s| self.reconstruct_statement(s).0).collect(),
.statements
.into_iter()
.map(|s| self.reconstruct_statement(s).0)
.collect(),
span: input.span, span: input.span,
}; };
@ -46,32 +41,28 @@ impl StatementReconstructor for Unroller<'_> {
fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) { fn reconstruct_definition(&mut self, input: DefinitionStatement) -> (Statement, Self::AdditionalOutput) {
// If we are unrolling a loop, then we need to repopulate the symbol table. // If we are unrolling a loop, then we need to repopulate the symbol table.
if self.is_unrolling { if self.is_unrolling {
let declaration = if input.declaration_type == DeclarationType::Const { let declaration =
VariableType::Const if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut };
} else {
VariableType::Mut
};
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| { let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) =
symbol, self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration })
VariableSymbol { {
type_,
span,
declaration,
},
) {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
}; };
// Insert the variables in the into the symbol table. // Insert the variables in the into the symbol table.
match &input.place { match &input.place {
Expression::Identifier(identifier) => insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration), Expression::Identifier(identifier) => {
insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration)
}
Expression::Tuple(tuple_expression) => { Expression::Tuple(tuple_expression) => {
let tuple_type = match input.type_ { let tuple_type = match input.type_ {
Type::Tuple(ref tuple_type) => tuple_type, Type::Tuple(ref tuple_type) => tuple_type,
_ => unreachable!("Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple.") _ => unreachable!(
"Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple."
),
}; };
tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| { tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| {
let identifier = match expression { let identifier = match expression {
@ -80,9 +71,10 @@ impl StatementReconstructor for Unroller<'_> {
}; };
insert_variable(identifier.name, type_.clone(), identifier.span, declaration) insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
}); });
}, }
_ => unreachable!("Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple.") _ => unreachable!(
"Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple."
),
} }
} }
(Statement::Definition(input), Default::default()) (Statement::Definition(input), Default::default())
@ -91,27 +83,22 @@ impl StatementReconstructor for Unroller<'_> {
fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) { fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
// We match on start and stop cause loops require // We match on start and stop cause loops require
// bounds to be constants. // bounds to be constants.
match ( match (input.start_value.clone().into_inner(), input.stop_value.clone().into_inner()) {
input.start_value.clone().into_inner(),
input.stop_value.clone().into_inner(),
) {
(Some(start), Some(stop)) => match (Type::from(&start), Type::from(&stop)) { (Some(start), Some(stop)) => match (Type::from(&start), Type::from(&stop)) {
(Type::Integer(IntegerType::I8), Type::Integer(IntegerType::I8)) (Type::Integer(IntegerType::I8), Type::Integer(IntegerType::I8))
| (Type::Integer(IntegerType::I16), Type::Integer(IntegerType::I16)) | (Type::Integer(IntegerType::I16), Type::Integer(IntegerType::I16))
| (Type::Integer(IntegerType::I32), Type::Integer(IntegerType::I32)) | (Type::Integer(IntegerType::I32), Type::Integer(IntegerType::I32))
| (Type::Integer(IntegerType::I64), Type::Integer(IntegerType::I64)) | (Type::Integer(IntegerType::I64), Type::Integer(IntegerType::I64))
| (Type::Integer(IntegerType::I128), Type::Integer(IntegerType::I128)) => ( | (Type::Integer(IntegerType::I128), Type::Integer(IntegerType::I128)) => {
self.unroll_iteration_statement::<i128>(input, start, stop), (self.unroll_iteration_statement::<i128>(input, start, stop), Default::default())
Default::default(), }
),
(Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U8)) (Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U8))
| (Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U16)) | (Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U16))
| (Type::Integer(IntegerType::U32), Type::Integer(IntegerType::U32)) | (Type::Integer(IntegerType::U32), Type::Integer(IntegerType::U32))
| (Type::Integer(IntegerType::U64), Type::Integer(IntegerType::U64)) | (Type::Integer(IntegerType::U64), Type::Integer(IntegerType::U64))
| (Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128)) => ( | (Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128)) => {
self.unroll_iteration_statement::<u128>(input, start, stop), (self.unroll_iteration_statement::<u128>(input, start, stop), Default::default())
Default::default(), }
),
_ => unreachable!("Type checking ensures that `start` and `stop` have the same type."), _ => unreachable!("Type checking ensures that `start` and `stop` have the same type."),
}, },
// If both loop bounds are not constant, then the loop is not unrolled. // If both loop bounds are not constant, then the loop is not unrolled.

View File

@ -15,8 +15,17 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use leo_ast::{ use leo_ast::{
Block, DeclarationType, DefinitionStatement, Expression, IntegerType, IterationStatement, Literal, Statement, Block,
StatementReconstructor, Type, Value, DeclarationType,
DefinitionStatement,
Expression,
IntegerType,
IterationStatement,
Literal,
Statement,
StatementReconstructor,
Type,
Value,
}; };
use std::cell::RefCell; use std::cell::RefCell;
@ -37,29 +46,19 @@ pub struct Unroller<'a> {
impl<'a> Unroller<'a> { impl<'a> Unroller<'a> {
pub(crate) fn new(symbol_table: SymbolTable, handler: &'a Handler) -> Self { pub(crate) fn new(symbol_table: SymbolTable, handler: &'a Handler) -> Self {
Self { Self { symbol_table: RefCell::new(symbol_table), scope_index: 0, handler, is_unrolling: false }
symbol_table: RefCell::new(symbol_table),
scope_index: 0,
handler,
is_unrolling: false,
}
} }
/// Returns the index of the current scope. /// Returns the index of the current scope.
/// Note that if we are in the midst of unrolling an IterationStatement, a new scope is created. /// Note that if we are in the midst of unrolling an IterationStatement, a new scope is created.
pub(crate) fn current_scope_index(&mut self) -> usize { pub(crate) fn current_scope_index(&mut self) -> usize {
if self.is_unrolling { if self.is_unrolling { self.symbol_table.borrow_mut().insert_block() } else { self.scope_index }
self.symbol_table.borrow_mut().insert_block()
} else {
self.scope_index
}
} }
/// Enters a child scope. /// Enters a child scope.
pub(crate) fn enter_scope(&mut self, index: usize) -> usize { pub(crate) fn enter_scope(&mut self, index: usize) -> usize {
let previous_symbol_table = std::mem::take(&mut self.symbol_table); let previous_symbol_table = std::mem::take(&mut self.symbol_table);
self.symbol_table self.symbol_table.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner())); self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner()));
core::mem::replace(&mut self.scope_index, 0) core::mem::replace(&mut self.scope_index, 0)
} }
@ -121,13 +120,11 @@ impl<'a> Unroller<'a> {
statements: match input.inclusive { statements: match input.inclusive {
true => { true => {
let iter = RangeIterator::new(start, stop, Clusivity::Inclusive); let iter = RangeIterator::new(start, stop, Clusivity::Inclusive);
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)) iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)).collect()
.collect()
} }
false => { false => {
let iter = RangeIterator::new(start, stop, Clusivity::Exclusive); let iter = RangeIterator::new(start, stop, Clusivity::Exclusive);
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)) iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)).collect()
.collect()
} }
}, },
}); });
@ -201,10 +198,7 @@ impl<'a> Unroller<'a> {
statements.push(self.reconstruct_statement(s).0); statements.push(self.reconstruct_statement(s).0);
}); });
let block = Statement::Block(Block { let block = Statement::Block(Block { statements, span: input.block.span });
statements,
span: input.block.span,
});
self.is_unrolling = prior_is_unrolling; self.is_unrolling = prior_is_unrolling;

View File

@ -17,9 +17,24 @@
use crate::StaticSingleAssigner; use crate::StaticSingleAssigner;
use leo_ast::{ use leo_ast::{
AccessExpression, AssociatedFunction, BinaryExpression, CallExpression, Expression, ExpressionConsumer, Identifier, AccessExpression,
Literal, MemberAccess, Statement, Struct, StructExpression, StructVariableInitializer, TernaryExpression, AssociatedFunction,
TupleAccess, TupleExpression, UnaryExpression, UnitExpression, BinaryExpression,
CallExpression,
Expression,
ExpressionConsumer,
Identifier,
Literal,
MemberAccess,
Statement,
Struct,
StructExpression,
StructVariableInitializer,
TernaryExpression,
TupleAccess,
TupleExpression,
UnaryExpression,
UnitExpression,
}; };
use leo_span::{sym, Symbol}; use leo_span::{sym, Symbol};
@ -100,14 +115,12 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
statements.append(&mut right_statements); statements.append(&mut right_statements);
// Construct and accumulate a unique assignment statement storing the result of the binary expression. // Construct and accumulate a unique assignment statement storing the result of the binary expression.
let (place, statement) = self let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Binary(BinaryExpression {
.assigner left: Box::new(left_expression),
.unique_simple_assign_statement(Expression::Binary(BinaryExpression { right: Box::new(right_expression),
left: Box::new(left_expression), op: input.op,
right: Box::new(right_expression), span: input.span,
op: input.op, }));
span: input.span,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)
@ -129,16 +142,14 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
.collect(); .collect();
// Construct and accumulate a new assignment statement for the call expression. // Construct and accumulate a new assignment statement for the call expression.
let (place, statement) = self let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Call(CallExpression {
.assigner // Note that we do not rename the function name.
.unique_simple_assign_statement(Expression::Call(CallExpression { function: input.function,
// Note that we do not rename the function name. // Consume the arguments.
function: input.function, arguments,
// Consume the arguments. external: input.external,
arguments, span: input.span,
external: input.external, }));
span: input.span,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)
@ -165,10 +176,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
statements.append(&mut stmts); statements.append(&mut stmts);
// Return the new member. // Return the new member.
StructVariableInitializer { StructVariableInitializer { identifier: arg.identifier, expression: Some(expression) }
identifier: arg.identifier,
expression: Some(expression),
}
}) })
.collect(); .collect();
@ -182,10 +190,8 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
let mut reordered_members = Vec::with_capacity(members.len()); let mut reordered_members = Vec::with_capacity(members.len());
// Collect the members of the init expression into a map. // Collect the members of the init expression into a map.
let mut member_map: IndexMap<Symbol, StructVariableInitializer> = members let mut member_map: IndexMap<Symbol, StructVariableInitializer> =
.into_iter() members.into_iter().map(|member| (member.identifier.name, member)).collect();
.map(|member| (member.identifier.name, member))
.collect();
// If we are initializing a record, add the `owner` and `gates` fields, first and second respectively. // If we are initializing a record, add the `owner` and `gates` fields, first and second respectively.
// Note that type checking guarantees that the above fields exist. // Note that type checking guarantees that the above fields exist.
@ -209,13 +215,11 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
} }
// Construct and accumulate a new assignment statement for the struct expression. // Construct and accumulate a new assignment statement for the struct expression.
let (place, statement) = self let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Struct(StructExpression {
.assigner name: input.name,
.unique_simple_assign_statement(Expression::Struct(StructExpression { span: input.span,
name: input.name, members: reordered_members,
span: input.span, }));
members: reordered_members,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)
@ -237,13 +241,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
false => *self.rename_table.lookup(identifier.name).unwrap_or(&identifier.name), false => *self.rename_table.lookup(identifier.name).unwrap_or(&identifier.name),
}; };
( (Expression::Identifier(Identifier { name, span: identifier.span }), Default::default())
Expression::Identifier(Identifier {
name,
span: identifier.span,
}),
Default::default(),
)
} }
/// Consumes and returns the literal without making any modifications. /// Consumes and returns the literal without making any modifications.
@ -265,14 +263,12 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
statements.append(&mut if_false_statements); statements.append(&mut if_false_statements);
// Construct and accumulate a unique assignment statement storing the result of the ternary expression. // Construct and accumulate a unique assignment statement storing the result of the ternary expression.
let (place, statement) = self let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Ternary(TernaryExpression {
.assigner condition: Box::new(cond_expr),
.unique_simple_assign_statement(Expression::Ternary(TernaryExpression { if_true: Box::new(if_true_expr),
condition: Box::new(cond_expr), if_false: Box::new(if_false_expr),
if_true: Box::new(if_true_expr), span: input.span,
if_false: Box::new(if_false_expr), }));
span: input.span,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)
@ -296,10 +292,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
// Construct and accumulate a new assignment statement for the tuple expression. // Construct and accumulate a new assignment statement for the tuple expression.
let (place, statement) = self let (place, statement) = self
.assigner .assigner
.unique_simple_assign_statement(Expression::Tuple(TupleExpression { .unique_simple_assign_statement(Expression::Tuple(TupleExpression { elements, span: input.span }));
elements,
span: input.span,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)
@ -311,13 +304,11 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
let (receiver, mut statements) = self.consume_expression(*input.receiver); let (receiver, mut statements) = self.consume_expression(*input.receiver);
// Construct and accumulate a new assignment statement for the unary expression. // Construct and accumulate a new assignment statement for the unary expression.
let (place, statement) = self let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Unary(UnaryExpression {
.assigner op: input.op,
.unique_simple_assign_statement(Expression::Unary(UnaryExpression { receiver: Box::new(receiver),
op: input.op, span: input.span,
receiver: Box::new(receiver), }));
span: input.span,
}));
statements.push(statement); statements.push(statement);
(Expression::Identifier(place), statements) (Expression::Identifier(place), statements)

View File

@ -17,8 +17,18 @@
use crate::StaticSingleAssigner; use crate::StaticSingleAssigner;
use leo_ast::{ use leo_ast::{
Block, Finalize, Function, FunctionConsumer, Member, Program, ProgramConsumer, ProgramScope, ProgramScopeConsumer, Block,
StatementConsumer, Struct, StructConsumer, Finalize,
Function,
FunctionConsumer,
Member,
Program,
ProgramConsumer,
ProgramScope,
ProgramScopeConsumer,
StatementConsumer,
Struct,
StructConsumer,
}; };
use leo_span::{sym, Symbol}; use leo_span::{sym, Symbol};
@ -33,11 +43,8 @@ impl StructConsumer for StaticSingleAssigner<'_> {
false => struct_, false => struct_,
true => { true => {
let mut members = Vec::with_capacity(struct_.members.len()); let mut members = Vec::with_capacity(struct_.members.len());
let mut member_map: IndexMap<Symbol, Member> = struct_ let mut member_map: IndexMap<Symbol, Member> =
.members struct_.members.into_iter().map(|member| (member.identifier.name, member)).collect();
.into_iter()
.map(|member| (member.identifier.name, member))
.collect();
// Add the owner field to the beginning of the members list. // Add the owner field to the beginning of the members list.
// Note that type checking ensures that the owner field exists. // Note that type checking ensures that the owner field exists.
@ -67,14 +74,10 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
// There is no need to reconstruct `function.inputs`. // There is no need to reconstruct `function.inputs`.
// However, for each input, we must add each symbol to the rename table. // However, for each input, we must add each symbol to the rename table.
for input_variable in function.input.iter() { for input_variable in function.input.iter() {
self.rename_table self.rename_table.update(input_variable.identifier().name, input_variable.identifier().name);
.update(input_variable.identifier().name, input_variable.identifier().name);
} }
let block = Block { let block = Block { span: function.block.span, statements: self.consume_block(function.block) };
span: function.block.span,
statements: self.consume_block(function.block),
};
// Remove the `RenameTable` for the function. // Remove the `RenameTable` for the function.
self.pop(); self.pop();
@ -86,14 +89,10 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
// There is no need to reconstruct `finalize.inputs`. // There is no need to reconstruct `finalize.inputs`.
// However, for each input, we must add each symbol to the rename table. // However, for each input, we must add each symbol to the rename table.
for input_variable in finalize.input.iter() { for input_variable in finalize.input.iter() {
self.rename_table self.rename_table.update(input_variable.identifier().name, input_variable.identifier().name);
.update(input_variable.identifier().name, input_variable.identifier().name);
} }
let block = Block { let block = Block { span: finalize.block.span, statements: self.consume_block(finalize.block) };
span: finalize.block.span,
statements: self.consume_block(finalize.block),
};
// Remove the `RenameTable` for the finalize block. // Remove the `RenameTable` for the finalize block.
self.pop(); self.pop();
@ -128,17 +127,9 @@ impl ProgramScopeConsumer for StaticSingleAssigner<'_> {
fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output { fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output {
ProgramScope { ProgramScope {
program_id: input.program_id, program_id: input.program_id,
structs: input structs: input.structs.into_iter().map(|(i, s)| (i, self.consume_struct(s))).collect(),
.structs
.into_iter()
.map(|(i, s)| (i, self.consume_struct(s)))
.collect(),
mappings: input.mappings, mappings: input.mappings,
functions: input functions: input.functions.into_iter().map(|(i, f)| (i, self.consume_function(f))).collect(),
.functions
.into_iter()
.map(|(i, f)| (i, self.consume_function(f)))
.collect(),
span: input.span, span: input.span,
} }
} }

View File

@ -17,9 +17,25 @@
use crate::{RenameTable, StaticSingleAssigner}; use crate::{RenameTable, StaticSingleAssigner};
use leo_ast::{ use leo_ast::{
AssertStatement, AssertVariant, AssignStatement, Block, CallExpression, ConditionalStatement, ConsoleStatement, AssertStatement,
DecrementStatement, DefinitionStatement, Expression, ExpressionConsumer, ExpressionStatement, Identifier, AssertVariant,
IncrementStatement, IterationStatement, ReturnStatement, Statement, StatementConsumer, TernaryExpression, AssignStatement,
Block,
CallExpression,
ConditionalStatement,
ConsoleStatement,
DecrementStatement,
DefinitionStatement,
Expression,
ExpressionConsumer,
ExpressionStatement,
Identifier,
IncrementStatement,
IterationStatement,
ReturnStatement,
Statement,
StatementConsumer,
TernaryExpression,
TupleExpression, TupleExpression,
}; };
use leo_span::Symbol; use leo_span::Symbol;
@ -59,10 +75,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
}; };
// Add the assert statement to the list of produced statements. // Add the assert statement to the list of produced statements.
statements.push(Statement::Assert(AssertStatement { statements.push(Statement::Assert(AssertStatement { variant, span: input.span }));
variant,
span: input.span,
}));
statements statements
} }
@ -88,11 +101,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
/// Consumes a `Block`, flattening its constituent `ConditionalStatement`s. /// Consumes a `Block`, flattening its constituent `ConditionalStatement`s.
fn consume_block(&mut self, block: Block) -> Self::Output { fn consume_block(&mut self, block: Block) -> Self::Output {
block block.statements.into_iter().flat_map(|statement| self.consume_statement(statement)).collect()
.statements
.into_iter()
.flat_map(|statement| self.consume_statement(statement))
.collect()
} }
/// Consumes a `ConditionalStatement`, producing phi functions (assign statements) for variables written in the then-block and otherwise-block. /// Consumes a `ConditionalStatement`, producing phi functions (assign statements) for variables written in the then-block and otherwise-block.
@ -110,10 +119,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
self.push(); self.push();
// Consume the then-block. // Consume the then-block.
let then = Block { let then = Block { span: conditional.then.span, statements: self.consume_block(conditional.then) };
span: conditional.then.span,
statements: self.consume_block(conditional.then),
};
// Remove the `RenameTable` for the then-block. // Remove the `RenameTable` for the then-block.
let if_table = self.pop(); let if_table = self.pop();
@ -156,13 +162,9 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
if self.rename_table.lookup(**symbol).is_some() { if self.rename_table.lookup(**symbol).is_some() {
// Helper to lookup a symbol and create an argument for the phi function. // Helper to lookup a symbol and create an argument for the phi function.
let create_phi_argument = |table: &RenameTable, symbol: Symbol| { let create_phi_argument = |table: &RenameTable, symbol: Symbol| {
let name = *table let name =
.lookup(symbol) *table.lookup(symbol).unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program."));
.unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program.")); Box::new(Expression::Identifier(Identifier { name, span: Default::default() }))
Box::new(Expression::Identifier(Identifier {
name,
span: Default::default(),
}))
}; };
// Create a new name for the variable written to in the `ConditionalStatement`. // Create a new name for the variable written to in the `ConditionalStatement`.
@ -178,13 +180,9 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
statements.extend(stmts); statements.extend(stmts);
// Create a new `AssignStatement` for the phi function. // Create a new `AssignStatement` for the phi function.
let assignment = self.assigner.simple_assign_statement( let assignment = self
Identifier { .assigner
name: new_name, .simple_assign_statement(Identifier { name: new_name, span: Default::default() }, value);
span: Default::default(),
},
value,
);
// Update the `RenameTable` with the new name of the variable. // Update the `RenameTable` with the new name of the variable.
self.rename_table.update(*(*symbol), new_name); self.rename_table.update(*(*symbol), new_name);
@ -251,15 +249,14 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
} }
}).collect(); }).collect();
statements.push(Statement::Assign(Box::new(AssignStatement { statements.push(Statement::Assign(Box::new(AssignStatement {
place: Expression::Tuple(TupleExpression { place: Expression::Tuple(TupleExpression { elements, span: Default::default() }),
elements,
span: Default::default()
}),
value, value,
span: Default::default() span: Default::default(),
}))); })));
} }
_ => unreachable!("Type checking guarantees that the left-hand-side of a `DefinitionStatement` is an identifier or tuple."), _ => unreachable!(
"Type checking guarantees that the left-hand-side of a `DefinitionStatement` is an identifier or tuple."
),
} }
self.is_lhs = false; self.is_lhs = false;

View File

@ -30,12 +30,7 @@ pub struct StaticSingleAssigner<'a> {
impl<'a> StaticSingleAssigner<'a> { impl<'a> StaticSingleAssigner<'a> {
/// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`. /// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`.
pub(crate) fn new(symbol_table: &'a SymbolTable) -> Self { pub(crate) fn new(symbol_table: &'a SymbolTable) -> Self {
Self { Self { symbol_table, rename_table: RenameTable::new(None), is_lhs: false, assigner: Assigner::default() }
symbol_table,
rename_table: RenameTable::new(None),
is_lhs: false,
assigner: Assigner::default(),
}
} }
/// Pushes a new scope, setting the current scope as the new scope's parent. /// Pushes a new scope, setting the current scope as the new scope's parent.

View File

@ -31,10 +31,7 @@ pub struct SymbolTableCreator<'a> {
impl<'a> SymbolTableCreator<'a> { impl<'a> SymbolTableCreator<'a> {
pub fn new(handler: &'a Handler) -> Self { pub fn new(handler: &'a Handler) -> Self {
Self { Self { symbol_table: Default::default(), handler }
symbol_table: Default::default(),
handler,
}
} }
} }
@ -58,17 +55,14 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
fn visit_mapping(&mut self, input: &'a Mapping) { fn visit_mapping(&mut self, input: &'a Mapping) {
// Add the variable associated with the mapping to the symbol table. // Add the variable associated with the mapping to the symbol table.
if let Err(err) = self.symbol_table.insert_variable( if let Err(err) = self.symbol_table.insert_variable(input.identifier.name, VariableSymbol {
input.identifier.name, type_: Type::Mapping(MappingType {
VariableSymbol { key: Box::new(input.key_type.clone()),
type_: Type::Mapping(MappingType { value: Box::new(input.value_type.clone()),
key: Box::new(input.key_type.clone()), }),
value: Box::new(input.value_type.clone()), span: input.span,
}), declaration: VariableType::Mut,
span: input.span, }) {
declaration: VariableType::Mut,
},
) {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
} }

View File

@ -17,8 +17,7 @@
use crate::TypeChecker; use crate::TypeChecker;
use leo_ast::*; use leo_ast::*;
use leo_errors::emitter::Handler; use leo_errors::{emitter::Handler, TypeCheckerError};
use leo_errors::TypeCheckerError;
use leo_span::{sym, Span}; use leo_span::{sym, Span};
use std::str::FromStr; use std::str::FromStr;
@ -28,11 +27,7 @@ fn return_incorrect_type(t1: Option<Type>, t2: Option<Type>, expected: &Option<T
(Some(t1), Some(t2)) if t1 == t2 => Some(t1), (Some(t1), Some(t2)) if t1 == t2 => Some(t1),
(Some(t1), Some(t2)) => { (Some(t1), Some(t2)) => {
if let Some(expected) = expected { if let Some(expected) = expected {
if &t1 != expected { if &t1 != expected { Some(t1) } else { Some(t2) }
Some(t1)
} else {
Some(t2)
}
} else { } else {
Some(t1) Some(t1)
} }
@ -482,12 +477,9 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
} }
// Check function argument types. // Check function argument types.
func.input func.input.iter().zip(input.arguments.iter()).for_each(|(expected, argument)| {
.iter() self.visit_expression(argument, &Some(expected.type_()));
.zip(input.arguments.iter()) });
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_()));
});
// Add the call to the call graph. // Add the call to the call graph.
let caller_name = match self.function { let caller_name = match self.function {
@ -524,11 +516,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
// Check struct member types. // Check struct member types.
struct_.members.iter().for_each(|Member { identifier, type_, .. }| { struct_.members.iter().for_each(|Member { identifier, type_, .. }| {
// Lookup struct variable name. // Lookup struct variable name.
if let Some(actual) = input if let Some(actual) = input.members.iter().find(|member| member.identifier.name == identifier.name) {
.members
.iter()
.find(|member| member.identifier.name == identifier.name)
{
match &actual.expression { match &actual.expression {
// If `expression` is None, then the member uses the identifier shorthand, e.g. `Foo { a }` // If `expression` is None, then the member uses the identifier shorthand, e.g. `Foo { a }`
None => self.visit_identifier(&actual.identifier, &Some(type_.clone())), None => self.visit_identifier(&actual.identifier, &Some(type_.clone())),
@ -546,11 +534,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
Some(ret) Some(ret)
} else { } else {
self.emit_err(TypeCheckerError::unknown_sym( self.emit_err(TypeCheckerError::unknown_sym("struct", input.name.name, input.name.span()));
"struct",
input.name.name,
input.name.span(),
));
None None
} }
} }
@ -655,16 +639,13 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
)); ));
} }
expected_types expected_types.iter().zip(input.elements.iter()).for_each(|(expected, expr)| {
.iter() // Check that the component expression is not a tuple.
.zip(input.elements.iter()) if matches!(expr, Expression::Tuple(_)) {
.for_each(|(expected, expr)| { self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()))
// Check that the component expression is not a tuple. }
if matches!(expr, Expression::Tuple(_)) { self.visit_expression(expr, &Some(expected.clone()));
self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span())) });
}
self.visit_expression(expr, &Some(expected.clone()));
});
Some(Type::Tuple(expected_types.clone())) Some(Type::Tuple(expected_types.clone()))
} else { } else {
@ -727,9 +708,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
fn visit_unit(&mut self, input: &'a UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output { fn visit_unit(&mut self, input: &'a UnitExpression, _additional: &Self::AdditionalInput) -> Self::Output {
// Unit expression are only allowed inside a return statement. // Unit expression are only allowed inside a return statement.
if !self.is_return { if !self.is_return {
self.emit_err(TypeCheckerError::unit_expression_only_in_return_statements( self.emit_err(TypeCheckerError::unit_expression_only_in_return_statements(input.span()));
input.span(),
));
} }
Some(Type::Unit) Some(Type::Unit)
} }

View File

@ -48,10 +48,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
} }
// Typecheck the program scopes. // Typecheck the program scopes.
input input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
.program_scopes
.values()
.for_each(|scope| self.visit_program_scope(scope));
} }
fn visit_program_scope(&mut self, input: &'a ProgramScope) { fn visit_program_scope(&mut self, input: &'a ProgramScope) {
@ -94,18 +91,11 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Check for conflicting struct/record member names. // Check for conflicting struct/record member names.
let mut used = HashSet::new(); let mut used = HashSet::new();
// TODO: Better span to target duplicate member. // TODO: Better span to target duplicate member.
if !input.members.iter().all( if !input.members.iter().all(|Member { identifier, type_, span, .. }| {
|Member { // Check that the member types are defined.
identifier, self.assert_type_is_defined(type_, *span);
type_, used.insert(identifier.name)
span, }) {
..
}| {
// Check that the member types are defined.
self.assert_type_is_defined(type_, *span);
used.insert(identifier.name)
},
) {
self.emit_err(if input.is_record { self.emit_err(if input.is_record {
TypeCheckerError::duplicate_record_variable(input.name(), input.span()) TypeCheckerError::duplicate_record_variable(input.name(), input.span())
} else { } else {
@ -121,31 +111,17 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
}) { }) {
Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type! Some((_, actual_ty)) if expected_ty.eq_flat(actual_ty) => {} // All good, found + right type!
Some((field, _)) => { Some((field, _)) => {
self.emit_err(TypeCheckerError::record_var_wrong_type( self.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()));
field,
expected_ty,
input.span(),
));
} }
None => { None => {
self.emit_err(TypeCheckerError::required_record_variable( self.emit_err(TypeCheckerError::required_record_variable(need, expected_ty, input.span()));
need,
expected_ty,
input.span(),
));
} }
}; };
check_has_field(sym::owner, Type::Address); check_has_field(sym::owner, Type::Address);
check_has_field(sym::gates, Type::Integer(IntegerType::U64)); check_has_field(sym::gates, Type::Integer(IntegerType::U64));
} }
for Member { for Member { mode, identifier, type_, span } in input.members.iter() {
mode,
identifier,
type_,
span,
} in input.members.iter()
{
// Check that the member type is not a tuple. // Check that the member type is not a tuple.
if matches!(type_, Type::Tuple(_)) { if matches!(type_, Type::Tuple(_)) {
self.emit_err(TypeCheckerError::composite_data_type_cannot_contain_tuple( self.emit_err(TypeCheckerError::composite_data_type_cannot_contain_tuple(
@ -201,12 +177,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Lookup function metadata in the symbol table. // Lookup function metadata in the symbol table.
// Note that this unwrap is safe since function metadata is stored in a prior pass. // Note that this unwrap is safe since function metadata is stored in a prior pass.
let function_index = self let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
.symbol_table
.borrow()
.lookup_fn_symbol(function.identifier.name)
.unwrap()
.id;
// Enter the function's scope. // Enter the function's scope.
self.enter_scope(function_index); self.enter_scope(function_index);
@ -235,25 +206,24 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Note that this unwrap is safe since we assign to `self.variant` above. // Note that this unwrap is safe since we assign to `self.variant` above.
match self.variant.unwrap() { match self.variant.unwrap() {
// If the function is a transition function, then check that the parameter mode is not a constant. // If the function is a transition function, then check that the parameter mode is not a constant.
Variant::Transition if input_var.mode() == Mode::Constant => self.emit_err( Variant::Transition if input_var.mode() == Mode::Constant => {
TypeCheckerError::transition_function_inputs_cannot_be_const(input_var.span()), self.emit_err(TypeCheckerError::transition_function_inputs_cannot_be_const(input_var.span()))
), }
// If the function is not a transition function, then check that the parameters do not have an associated mode. // If the function is not a transition function, then check that the parameters do not have an associated mode.
Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => self.emit_err( Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => {
TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()), self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()))
), }
_ => {} // Do nothing. _ => {} // Do nothing.
} }
// Check for conflicting variable names. // Check for conflicting variable names.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) =
input_var.identifier().name, self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
VariableSymbol {
type_: input_var.type_(), type_: input_var.type_(),
span: input_var.identifier().span(), span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()), declaration: VariableType::Input(input_var.mode()),
}, })
) { {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
}); });
@ -277,12 +247,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// If the function is not a transition function, then it cannot output a record. // If the function is not a transition function, then it cannot output a record.
if let Type::Identifier(identifier) = function_output.type_ { if let Type::Identifier(identifier) = function_output.type_ {
if !matches!(function.variant, Variant::Transition) if !matches!(function.variant, Variant::Transition)
&& self && self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record
.symbol_table
.borrow()
.lookup_struct(identifier.name)
.unwrap()
.is_record
{ {
self.emit_err(TypeCheckerError::function_cannot_output_record(function_output.span)); self.emit_err(TypeCheckerError::function_cannot_output_record(function_output.span));
} }
@ -325,9 +290,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Check that the function is a transition function. // Check that the function is a transition function.
if !matches!(function.variant, Variant::Transition) { if !matches!(function.variant, Variant::Transition) {
self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize( self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize(finalize.span));
finalize.span,
));
} }
// Check that the name of the finalize block matches the function name. // Check that the name of the finalize block matches the function name.
@ -354,14 +317,13 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span())); self.emit_err(TypeCheckerError::finalize_input_mode_must_be_public(input_var.span()));
} }
// Check for conflicting variable names. // Check for conflicting variable names.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) =
input_var.identifier().name, self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
VariableSymbol {
type_: input_var.type_(), type_: input_var.type_(),
span: input_var.identifier().span(), span: input_var.identifier().span(),
declaration: VariableType::Input(input_var.mode()), declaration: VariableType::Input(input_var.mode()),
}, })
) { {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
}); });
@ -378,9 +340,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
// Check that the mode of the output is valid. // Check that the mode of the output is valid.
// Note that a finalize block can have only public outputs. // Note that a finalize block can have only public outputs.
if matches!(output_type.mode(), Mode::Constant | Mode::Private) { if matches!(output_type.mode(), Mode::Constant | Mode::Private) {
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public( self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(output_type.span()));
output_type.span(),
));
} }
}); });

View File

@ -162,10 +162,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
self.assert_mapping_type(&mapping_type, input.span()); self.assert_mapping_type(&mapping_type, input.span());
match mapping_type { match mapping_type {
None => self.emit_err(TypeCheckerError::could_not_determine_type( None => self.emit_err(TypeCheckerError::could_not_determine_type(input.mapping, input.mapping.span)),
input.mapping,
input.mapping.span,
)),
Some(Type::Mapping(mapping_type)) => { Some(Type::Mapping(mapping_type)) => {
// Check that the index matches the key type of the mapping. // Check that the index matches the key type of the mapping.
let index_type = self.visit_expression(&input.index, &None); let index_type = self.visit_expression(&input.index, &None);
@ -178,20 +175,15 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Check that the amount type is incrementable. // Check that the amount type is incrementable.
self.assert_field_group_scalar_int_type(&amount_type, input.amount.span()); self.assert_field_group_scalar_int_type(&amount_type, input.amount.span());
} }
Some(mapping_type) => self.emit_err(TypeCheckerError::expected_one_type_of( Some(mapping_type) => {
"mapping", self.emit_err(TypeCheckerError::expected_one_type_of("mapping", mapping_type, input.mapping.span))
mapping_type, }
input.mapping.span,
)),
} }
} }
fn visit_definition(&mut self, input: &'a DefinitionStatement) { fn visit_definition(&mut self, input: &'a DefinitionStatement) {
let declaration = if input.declaration_type == DeclarationType::Const { let declaration =
VariableType::Const if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut };
} else {
VariableType::Mut
};
// Check that the type of the definition is defined. // Check that the type of the definition is defined.
self.assert_type_is_defined(&input.type_, input.span); self.assert_type_is_defined(&input.type_, input.span);
@ -220,14 +212,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// TODO: Dedup with unrolling pass. // TODO: Dedup with unrolling pass.
// Helper to insert the variables into the symbol table. // Helper to insert the variables into the symbol table.
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| { let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) =
symbol, self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration })
VariableSymbol { {
type_,
span,
declaration,
},
) {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
}; };
@ -244,21 +231,17 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
"Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple." "Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple."
), ),
}; };
tuple_expression tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| {
.elements let identifier = match expression {
.iter() Expression::Identifier(identifier) => identifier,
.zip_eq(tuple_type.0.iter()) _ => {
.for_each(|(expression, type_)| { return self.emit_err(TypeCheckerError::lhs_tuple_element_must_be_an_identifier(
let identifier = match expression { expression.span(),
Expression::Identifier(identifier) => identifier, ));
_ => { }
return self.emit_err(TypeCheckerError::lhs_tuple_element_must_be_an_identifier( };
expression.span(), insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
)) });
}
};
insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
});
} }
_ => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.place.span())), _ => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.place.span())),
} }
@ -267,9 +250,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
fn visit_expression_statement(&mut self, input: &'a ExpressionStatement) { fn visit_expression_statement(&mut self, input: &'a ExpressionStatement) {
// Expression statements can only be function calls. // Expression statements can only be function calls.
if !matches!(input.expression, Expression::Call(_)) { if !matches!(input.expression, Expression::Call(_)) {
self.emit_err(TypeCheckerError::expression_statement_must_be_function_call( self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
input.span(),
));
} else { } else {
// Check the expression. // Check the expression.
// TODO: Should the output type be restricted to unit types? // TODO: Should the output type be restricted to unit types?
@ -287,10 +268,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
self.assert_mapping_type(&mapping_type, input.span()); self.assert_mapping_type(&mapping_type, input.span());
match mapping_type { match mapping_type {
None => self.emit_err(TypeCheckerError::could_not_determine_type( None => self.emit_err(TypeCheckerError::could_not_determine_type(input.mapping, input.mapping.span)),
input.mapping,
input.mapping.span,
)),
Some(Type::Mapping(mapping_type)) => { Some(Type::Mapping(mapping_type)) => {
// Check that the index matches the key type of the mapping. // Check that the index matches the key type of the mapping.
let index_type = self.visit_expression(&input.index, &None); let index_type = self.visit_expression(&input.index, &None);
@ -303,11 +281,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Check that the amount type is incrementable. // Check that the amount type is incrementable.
self.assert_field_group_scalar_int_type(&amount_type, input.amount.span()); self.assert_field_group_scalar_int_type(&amount_type, input.amount.span());
} }
Some(mapping_type) => self.emit_err(TypeCheckerError::expected_one_type_of( Some(mapping_type) => {
"mapping", self.emit_err(TypeCheckerError::expected_one_type_of("mapping", mapping_type, input.mapping.span))
mapping_type, }
input.mapping.span,
)),
} }
} }
@ -319,14 +295,11 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
let scope_index = self.create_child_scope(); let scope_index = self.create_child_scope();
// Add the loop variable to the scope of the loop body. // Add the loop variable to the scope of the loop body.
if let Err(err) = self.symbol_table.borrow_mut().insert_variable( if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input.variable.name, VariableSymbol {
input.variable.name, type_: input.type_.clone(),
VariableSymbol { span: input.span(),
type_: input.type_.clone(), declaration: VariableType::Const,
span: input.span(), }) {
declaration: VariableType::Const,
},
) {
self.handler.emit_err(err); self.handler.emit_err(err);
} }
@ -372,16 +345,12 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// We can safely unwrap all self.parent instances because // We can safely unwrap all self.parent instances because
// statements should always have some parent block // statements should always have some parent block
let parent = self.function.unwrap(); let parent = self.function.unwrap();
let return_type = &self let return_type = &self.symbol_table.borrow().lookup_fn_symbol(parent).map(|f| match self.is_finalize {
.symbol_table // TODO: Check this.
.borrow() // Note that this `unwrap()` is safe since we checked that the function has a finalize block.
.lookup_fn_symbol(parent) true => f.finalize.as_ref().unwrap().output_type.clone(),
.map(|f| match self.is_finalize { false => f.output_type.clone(),
// TODO: Check this. });
// Note that this `unwrap()` is safe since we checked that the function has a finalize block.
true => f.finalize.as_ref().unwrap().output_type.clone(),
false => f.output_type.clone(),
});
// Set the `has_return` flag. // Set the `has_return` flag.
self.has_return = true; self.has_return = true;
@ -413,13 +382,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
// Check that the function has a finalize block. // Check that the function has a finalize block.
// Note that `self.function.unwrap()` is safe since every `self.function` is set for every function. // Note that `self.function.unwrap()` is safe since every `self.function` is set for every function.
// Note that `(self.function.unwrap()).unwrap()` is safe since all functions have been checked to exist. // Note that `(self.function.unwrap()).unwrap()` is safe since all functions have been checked to exist.
let finalize = self let finalize =
.symbol_table self.symbol_table.borrow().lookup_fn_symbol(self.function.unwrap()).unwrap().finalize.clone();
.borrow()
.lookup_fn_symbol(self.function.unwrap())
.unwrap()
.finalize
.clone();
match finalize { match finalize {
None => self.emit_err(TypeCheckerError::finalize_without_finalize_block(input.span())), None => self.emit_err(TypeCheckerError::finalize_without_finalize_block(input.span())),
Some(finalize) => { Some(finalize) => {
@ -433,13 +397,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
} }
// Check function argument types. // Check function argument types.
finalize finalize.input.iter().zip(arguments.iter()).for_each(|(expected, argument)| {
.input self.visit_expression(argument, &Some(expected.type_()));
.iter() });
.zip(arguments.iter())
.for_each(|(expected, argument)| {
self.visit_expression(argument, &Some(expected.type_()));
});
} }
} }
} }

View File

@ -87,11 +87,8 @@ const UNSIGNED_INT_TYPES: [Type; 5] = [
Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128),
]; ];
const MAGNITUDE_TYPES: [Type; 3] = [ const MAGNITUDE_TYPES: [Type; 3] =
Type::Integer(IntegerType::U8), [Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U32)];
Type::Integer(IntegerType::U16),
Type::Integer(IntegerType::U32),
];
impl<'a> TypeChecker<'a> { impl<'a> TypeChecker<'a> {
/// Returns a new type checker given a symbol table and error handler. /// Returns a new type checker given a symbol table and error handler.
@ -119,8 +116,7 @@ impl<'a> TypeChecker<'a> {
/// Enters a child scope. /// Enters a child scope.
pub(crate) fn enter_scope(&mut self, index: usize) { pub(crate) fn enter_scope(&mut self, index: usize) {
let previous_symbol_table = std::mem::take(&mut self.symbol_table); let previous_symbol_table = std::mem::take(&mut self.symbol_table);
self.symbol_table self.symbol_table.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner())); self.symbol_table.borrow_mut().parent = Some(Box::new(previous_symbol_table.into_inner()));
} }
@ -137,8 +133,7 @@ impl<'a> TypeChecker<'a> {
/// Exits the current scope. /// Exits the current scope.
pub(crate) fn exit_scope(&mut self, index: usize) { pub(crate) fn exit_scope(&mut self, index: usize) {
let previous_symbol_table = *self.symbol_table.borrow_mut().parent.take().unwrap(); let previous_symbol_table = *self.symbol_table.borrow_mut().parent.take().unwrap();
self.symbol_table self.symbol_table.swap(previous_symbol_table.lookup_scope_by_index(index).unwrap());
.swap(previous_symbol_table.lookup_scope_by_index(index).unwrap());
self.symbol_table = RefCell::new(previous_symbol_table); self.symbol_table = RefCell::new(previous_symbol_table);
} }
@ -183,22 +178,12 @@ impl<'a> TypeChecker<'a> {
/// Emits an error to the error handler if the `actual` type is not equal to the `expected` type. /// Emits an error to the error handler if the `actual` type is not equal to the `expected` type.
pub(crate) fn assert_type(&self, actual: &Option<Type>, expected: &Type, span: Span) { pub(crate) fn assert_type(&self, actual: &Option<Type>, expected: &Type, span: Span) {
self.check_type( self.check_type(|actual: &Type| actual.eq_flat(expected), expected.to_string(), actual, span)
|actual: &Type| actual.eq_flat(expected),
expected.to_string(),
actual,
span,
)
} }
/// Emits an error to the handler if the given type is not a boolean. /// Emits an error to the handler if the given type is not a boolean.
pub(crate) fn assert_bool_type(&self, type_: &Option<Type>, span: Span) { pub(crate) fn assert_bool_type(&self, type_: &Option<Type>, span: Span) {
self.check_type( self.check_type(|type_: &Type| BOOLEAN_TYPE.eq(type_), BOOLEAN_TYPE.to_string(), type_, span)
|type_: &Type| BOOLEAN_TYPE.eq(type_),
BOOLEAN_TYPE.to_string(),
type_,
span,
)
} }
/// Emits an error to the handler if the given type is not a field. /// Emits an error to the handler if the given type is not a field.
@ -213,22 +198,12 @@ impl<'a> TypeChecker<'a> {
/// Emits an error to the handler if the given type is not a scalar. /// Emits an error to the handler if the given type is not a scalar.
pub(crate) fn assert_scalar_type(&self, type_: &Option<Type>, span: Span) { pub(crate) fn assert_scalar_type(&self, type_: &Option<Type>, span: Span) {
self.check_type( self.check_type(|type_: &Type| SCALAR_TYPE.eq(type_), SCALAR_TYPE.to_string(), type_, span)
|type_: &Type| SCALAR_TYPE.eq(type_),
SCALAR_TYPE.to_string(),
type_,
span,
)
} }
/// Emits an error to the handler if the given type is not an integer. /// Emits an error to the handler if the given type is not an integer.
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) { pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
self.check_type( self.check_type(|type_: &Type| INT_TYPES.contains(type_), types_to_string(&INT_TYPES), type_, span)
|type_: &Type| INT_TYPES.contains(type_),
types_to_string(&INT_TYPES),
type_,
span,
)
} }
/// Emits an error to the handler if the given type is not a signed integer. /// Emits an error to the handler if the given type is not a signed integer.
@ -253,12 +228,7 @@ impl<'a> TypeChecker<'a> {
/// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32). /// Emits an error to the handler if the given type is not a magnitude (u8, u16, u32).
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) { pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
self.check_type( self.check_type(|type_: &Type| MAGNITUDE_TYPES.contains(type_), types_to_string(&MAGNITUDE_TYPES), type_, span)
|type_: &Type| MAGNITUDE_TYPES.contains(type_),
types_to_string(&MAGNITUDE_TYPES),
type_,
span,
)
} }
/// Emits an error to the handler if the given type is not a boolean or an integer. /// Emits an error to the handler if the given type is not a boolean or an integer.
@ -327,13 +297,7 @@ impl<'a> TypeChecker<'a> {
|type_: &Type| { |type_: &Type| {
FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | SCALAR_TYPE.eq(type_) | INT_TYPES.contains(type_) FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | SCALAR_TYPE.eq(type_) | INT_TYPES.contains(type_)
}, },
format!( format!("{}, {}, {}, {}", FIELD_TYPE, GROUP_TYPE, SCALAR_TYPE, types_to_string(&INT_TYPES),),
"{}, {}, {}, {}",
FIELD_TYPE,
GROUP_TYPE,
SCALAR_TYPE,
types_to_string(&INT_TYPES),
),
type_, type_,
span, span,
) )
@ -347,11 +311,7 @@ impl<'a> TypeChecker<'a> {
match CoreInstruction::from_symbols(ident.name, function.name) { match CoreInstruction::from_symbols(ident.name, function.name) {
None => { None => {
// Not a core library struct. // Not a core library struct.
self.emit_err(TypeCheckerError::invalid_core_function( self.emit_err(TypeCheckerError::invalid_core_function(ident.name, function.name, ident.span()));
ident.name,
function.name,
ident.span(),
));
} }
Some(core_instruction) => return Some(core_instruction), Some(core_instruction) => return Some(core_instruction),
} }
@ -380,11 +340,7 @@ impl<'a> TypeChecker<'a> {
.lookup_struct(identifier.name) .lookup_struct(identifier.name)
.map_or(false, |struct_| struct_.is_record) => .map_or(false, |struct_| struct_.is_record) =>
{ {
self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record( self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(parent, identifier.name, span))
parent,
identifier.name,
span,
))
} }
Type::Tuple(tuple_type) => { Type::Tuple(tuple_type) => {
for type_ in tuple_type.iter() { for type_ in tuple_type.iter() {
@ -423,12 +379,7 @@ impl<'a> TypeChecker<'a> {
/// Emits an error if the type is not a mapping. /// Emits an error if the type is not a mapping.
pub(crate) fn assert_mapping_type(&self, type_: &Option<Type>, span: Span) { pub(crate) fn assert_mapping_type(&self, type_: &Option<Type>, span: Span) {
self.check_type( self.check_type(|type_| matches!(type_, Type::Mapping(_)), "mapping".to_string(), type_, span)
|type_| matches!(type_, Type::Mapping(_)),
"mapping".to_string(),
type_,
span,
)
} }
} }

View File

@ -17,7 +17,9 @@
use crate::span::{BytePos, CharPos, Pos, Span}; use crate::span::{BytePos, CharPos, Pos, Span};
use std::{ use std::{
cell::RefCell, cell::RefCell,
fmt, fs, io, fmt,
fs,
io,
path::{Path, PathBuf}, path::{Path, PathBuf},
rc::Rc, rc::Rc,
}; };
@ -105,10 +107,7 @@ impl SourceMap {
if loc.line_start == loc.line_stop { if loc.line_start == loc.line_stop {
format!("{}:{}-{}", loc.line_start, loc.col_start, loc.col_stop) format!("{}:{}-{}", loc.line_start, loc.col_start, loc.col_stop)
} else { } else {
format!( format!("{}:{}-{}:{}", loc.line_start, loc.col_start, loc.line_stop, loc.col_stop)
"{}:{}-{}:{}",
loc.line_start, loc.col_start, loc.line_stop, loc.col_stop
)
} }
} }
@ -140,11 +139,7 @@ impl SourceMap {
let idx_lo = begin.lookup_line(span.lo).unwrap_or(0); let idx_lo = begin.lookup_line(span.lo).unwrap_or(0);
let idx_hi = begin.lookup_line(span.hi).unwrap_or(0) + 1; let idx_hi = begin.lookup_line(span.hi).unwrap_or(0) + 1;
let lo_line_pos = begin.lines[idx_lo]; let lo_line_pos = begin.lines[idx_lo];
let hi_line_pos = if idx_hi < begin.lines.len() { let hi_line_pos = if idx_hi < begin.lines.len() { begin.lines[idx_hi] } else { begin.end_pos };
begin.lines[idx_hi]
} else {
begin.end_pos
};
Some(begin.contents_of_span(Span::new(lo_line_pos, hi_line_pos))) Some(begin.contents_of_span(Span::new(lo_line_pos, hi_line_pos)))
} }
} }
@ -183,11 +178,7 @@ impl fmt::Display for FileName {
/// Is the env var `LEO_TESTFRAMEWORK` not enabled? /// Is the env var `LEO_TESTFRAMEWORK` not enabled?
pub fn is_not_test_framework() -> bool { pub fn is_not_test_framework() -> bool {
std::env::var("LEO_TESTFRAMEWORK") std::env::var("LEO_TESTFRAMEWORK").unwrap_or_default().trim().to_owned().is_empty()
.unwrap_or_default()
.trim()
.to_owned()
.is_empty()
} }
/// A single source in the [`SourceMap`]. /// A single source in the [`SourceMap`].
@ -215,14 +206,7 @@ impl SourceFile {
normalize_src(&mut src); normalize_src(&mut src);
let end_pos = start_pos + BytePos::from_usize(src.len()); let end_pos = start_pos + BytePos::from_usize(src.len());
let (lines, multibyte_chars) = analyze_source_file(&src, start_pos); let (lines, multibyte_chars) = analyze_source_file(&src, start_pos);
Self { Self { name, src, start_pos, end_pos, lines, multibyte_chars }
name,
src,
start_pos,
end_pos,
lines,
multibyte_chars,
}
} }
/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`. /// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.

View File

@ -42,10 +42,7 @@ impl Span {
/// Generates a dummy span with all defaults. /// Generates a dummy span with all defaults.
/// Should only be used in temporary situations. /// Should only be used in temporary situations.
pub const fn dummy() -> Self { pub const fn dummy() -> Self {
Self { Self { lo: BytePos(0), hi: BytePos(0) }
lo: BytePos(0),
hi: BytePos(0),
}
} }
/// Is the span a dummy? /// Is the span a dummy?

View File

@ -18,9 +18,12 @@
use crate::Span; use crate::Span;
use serde::de::{MapAccess, Visitor}; use serde::{
use serde::ser::SerializeMap; de::{MapAccess, Visitor},
use serde::{Deserializer, Serializer}; ser::SerializeMap,
Deserializer,
Serializer,
};
use std::fmt; use std::fmt;
/// The AST contains a few tuple-like enum variants that contain spans. /// The AST contains a few tuple-like enum variants that contain spans.

View File

@ -16,12 +16,15 @@
use crate::source_map::SourceMap; use crate::source_map::SourceMap;
use core::borrow::Borrow; use core::{
use core::cmp::PartialEq; borrow::Borrow,
use core::hash::{Hash, Hasher}; cmp::PartialEq,
use core::num::NonZeroU32; fmt,
use core::ops::Deref; hash::{Hash, Hasher},
use core::{fmt, str}; num::NonZeroU32,
ops::Deref,
str,
};
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexSet; use indexmap::IndexSet;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
@ -289,10 +292,7 @@ pub struct SessionGlobals {
impl Default for SessionGlobals { impl Default for SessionGlobals {
fn default() -> Self { fn default() -> Self {
Self { Self { symbol_interner: Interner::prefilled(), source_map: SourceMap::default() }
symbol_interner: Interner::prefilled(),
source_map: SourceMap::default(),
}
} }
} }
@ -381,9 +381,7 @@ impl Interner {
// arena: <_>::default(), // arena: <_>::default(),
set: init.iter().copied().map(InternedStr::Static).collect(), set: init.iter().copied().map(InternedStr::Static).collect(),
}; };
Self { Self { inner: RefCell::new(inner) }
inner: RefCell::new(inner),
}
} }
/// Interns `string`, returning a `Symbol` corresponding to it. /// Interns `string`, returning a `Symbol` corresponding to it.

View File

@ -68,13 +68,7 @@ impl<'a> Processor<'a> {
// we need a hashmap to pull rules easily // we need a hashmap to pull rules easily
let rules: HashMap<String, Rule> = abnf.into_iter().map(|rule| (rule.name().to_string(), rule)).collect(); let rules: HashMap<String, Rule> = abnf.into_iter().map(|rule| (rule.name().to_string(), rule)).collect();
Processor { Processor { grammar, line: 0, out: String::new(), rules, scope: Scope::Free }
grammar,
line: 0,
out: String::new(),
rules,
scope: Scope::Free,
}
} }
/// Main function for this struct. /// Main function for this struct.

View File

@ -64,15 +64,7 @@ impl Backtraced {
where where
S: ToString, S: ToString,
{ {
Self { Self { message: message.to_string(), help, code, code_identifier, type_, error, backtrace }
message: message.to_string(),
help,
code,
code_identifier,
type_,
error,
backtrace,
}
} }
/// Gets the backtraced error exit code. /// Gets the backtraced error exit code.
@ -113,11 +105,7 @@ impl Backtraced {
impl fmt::Display for Backtraced { impl fmt::Display for Backtraced {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (kind, code) = if self.error { let (kind, code) = if self.error { ("Error", self.error_code()) } else { ("Warning", self.warning_code()) };
("Error", self.error_code())
} else {
("Warning", self.warning_code())
};
let message = format!("{kind} [{code}]: {message}", message = self.message,); let message = format!("{kind} [{code}]: {message}", message = self.message,);
// To avoid the color enabling characters for comparison with test expectations. // To avoid the color enabling characters for comparison with test expectations.
@ -144,17 +132,13 @@ impl fmt::Display for Backtraced {
"1" => { "1" => {
let mut printer = BacktracePrinter::default(); let mut printer = BacktracePrinter::default();
printer = printer.lib_verbosity(Verbosity::Medium); printer = printer.lib_verbosity(Verbosity::Medium);
let trace = printer let trace = printer.format_trace_to_string(&self.backtrace).map_err(|_| fmt::Error)?;
.format_trace_to_string(&self.backtrace)
.map_err(|_| fmt::Error)?;
write!(f, "{trace}")?; write!(f, "{trace}")?;
} }
"full" => { "full" => {
let mut printer = BacktracePrinter::default(); let mut printer = BacktracePrinter::default();
printer = printer.lib_verbosity(Verbosity::Full); printer = printer.lib_verbosity(Verbosity::Full);
let trace = printer let trace = printer.format_trace_to_string(&self.backtrace).map_err(|_| fmt::Error)?;
.format_trace_to_string(&self.backtrace)
.map_err(|_| fmt::Error)?;
write!(f, "{trace}")?; write!(f, "{trace}")?;
} }
_ => {} _ => {}

View File

@ -109,32 +109,20 @@ impl fmt::Display for Formatted {
let (loc, contents) = with_session_globals(|s| { let (loc, contents) = with_session_globals(|s| {
( (
s.source_map s.source_map.span_to_location(self.span).unwrap_or_else(SpanLocation::dummy),
.span_to_location(self.span) s.source_map.line_contents_of_span(self.span).unwrap_or_else(|| "<contents unavailable>".to_owned()),
.unwrap_or_else(SpanLocation::dummy),
s.source_map
.line_contents_of_span(self.span)
.unwrap_or_else(|| "<contents unavailable>".to_owned()),
) )
}); });
let underlined = underline(loc.col_start, loc.col_stop); let underlined = underline(loc.col_start, loc.col_stop);
let (kind, code) = if self.backtrace.error { let (kind, code) =
("Error", self.error_code()) if self.backtrace.error { ("Error", self.error_code()) } else { ("Warning", self.warning_code()) };
} else {
("Warning", self.warning_code())
};
let message = format!("{kind} [{code}]: {message}", message = self.backtrace.message,); let message = format!("{kind} [{code}]: {message}", message = self.backtrace.message,);
// To avoid the color enabling characters for comparison with test expectations. // To avoid the color enabling characters for comparison with test expectations.
if std::env::var("LEO_TESTFRAMEWORK") if std::env::var("LEO_TESTFRAMEWORK").unwrap_or_default().trim().to_owned().is_empty() {
.unwrap_or_default()
.trim()
.to_owned()
.is_empty()
{
if self.backtrace.error { if self.backtrace.error {
write!(f, "{}", message.bold().red())?; write!(f, "{}", message.bold().red())?;
} else { } else {
@ -180,18 +168,14 @@ impl fmt::Display for Formatted {
let mut printer = BacktracePrinter::default(); let mut printer = BacktracePrinter::default();
printer = printer.verbosity(Verbosity::Medium); printer = printer.verbosity(Verbosity::Medium);
printer = printer.lib_verbosity(Verbosity::Medium); printer = printer.lib_verbosity(Verbosity::Medium);
let trace = printer let trace = printer.format_trace_to_string(&self.backtrace.backtrace).map_err(|_| fmt::Error)?;
.format_trace_to_string(&self.backtrace.backtrace)
.map_err(|_| fmt::Error)?;
write!(f, "\n{trace}")?; write!(f, "\n{trace}")?;
} }
"full" => { "full" => {
let mut printer = BacktracePrinter::default(); let mut printer = BacktracePrinter::default();
printer = printer.verbosity(Verbosity::Full); printer = printer.verbosity(Verbosity::Full);
printer = printer.lib_verbosity(Verbosity::Full); printer = printer.lib_verbosity(Verbosity::Full);
let trace = printer let trace = printer.format_trace_to_string(&self.backtrace.backtrace).map_err(|_| fmt::Error)?;
.format_trace_to_string(&self.backtrace.backtrace)
.map_err(|_| fmt::Error)?;
write!(f, "\n{trace}")?; write!(f, "\n{trace}")?;
} }
_ => {} _ => {}

View File

@ -17,10 +17,8 @@
use crate::LeoWarning; use crate::LeoWarning;
use super::LeoError; use super::LeoError;
use core::default::Default; use core::{default::Default, fmt};
use core::fmt; use std::{cell::RefCell, rc::Rc};
use std::cell::RefCell;
use std::rc::Rc;
/// Types that are sinks for compiler errors. /// Types that are sinks for compiler errors.
pub trait Emitter { pub trait Emitter {
@ -182,11 +180,7 @@ impl Default for Handler {
impl Handler { impl Handler {
/// Construct a `Handler` using the given `emitter`. /// Construct a `Handler` using the given `emitter`.
pub fn new(emitter: Box<dyn Emitter>) -> Self { pub fn new(emitter: Box<dyn Emitter>) -> Self {
let inner = RefCell::new(HandlerInner { let inner = RefCell::new(HandlerInner { err_count: 0, warn_count: 0, emitter });
err_count: 0,
warn_count: 0,
emitter,
});
Self { inner } Self { inner }
} }

View File

@ -14,14 +14,15 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::commands::ALEO_CLI_COMMAND; use crate::{
use crate::{commands::Command, context::Context}; commands::{Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_ast::Struct; use leo_ast::Struct;
use leo_compiler::{Compiler, CompilerOptions, InputAst}; use leo_compiler::{Compiler, CompilerOptions, InputAst};
use leo_errors::{CliError, CompilerError, PackageError, Result}; use leo_errors::{CliError, CompilerError, PackageError, Result};
use leo_package::source::SourceDirectory; use leo_package::{inputs::InputFile, outputs::OutputsDirectory, source::SourceDirectory};
use leo_package::{inputs::InputFile, outputs::OutputsDirectory};
use leo_span::symbol::with_session_globals; use leo_span::symbol::with_session_globals;
use aleo::commands::Build as AleoBuild; use aleo::commands::Build as AleoBuild;
@ -29,12 +30,13 @@ use aleo::commands::Build as AleoBuild;
use clap::StructOpt; use clap::StructOpt;
use indexmap::IndexMap; use indexmap::IndexMap;
use snarkvm::prelude::{ProgramID, Testnet3}; use snarkvm::prelude::{ProgramID, Testnet3};
use std::io::Write; use std::{
use std::path::{Path, PathBuf}; io::Write,
path::{Path, PathBuf},
};
use leo_errors::emitter::Handler; use leo_errors::emitter::Handler;
use leo_package::build::BuildDirectory; use leo_package::{build::BuildDirectory, imports::ImportsDirectory};
use leo_package::imports::ImportsDirectory;
use leo_span::Symbol; use leo_span::Symbol;
use tracing::span::Span; use tracing::span::Span;
@ -226,19 +228,14 @@ fn compile_leo_file(
is_import: bool, is_import: bool,
) -> Result<IndexMap<Symbol, Struct>> { ) -> Result<IndexMap<Symbol, Struct>> {
// Construct the Leo file name with extension `foo.leo`. // Construct the Leo file name with extension `foo.leo`.
let file_name = file_path let file_name =
.file_name() file_path.file_name().and_then(|name| name.to_str()).ok_or_else(PackageError::failed_to_get_file_name)?;
.and_then(|name| name.to_str())
.ok_or_else(PackageError::failed_to_get_file_name)?;
// If the program is an import, construct program name from file_path // If the program is an import, construct program name from file_path
// Otherwise, use the program_id found in `package.json`. // Otherwise, use the program_id found in `package.json`.
let program_name = match is_import { let program_name = match is_import {
false => program_id.name().to_string(), false => program_id.name().to_string(),
true => file_name true => file_name.strip_suffix(".leo").ok_or_else(PackageError::failed_to_get_file_name)?.to_string(),
.strip_suffix(".leo")
.ok_or_else(PackageError::failed_to_get_file_name)?
.to_string(),
}; };
// Create the path to the Aleo file. // Create the path to the Aleo file.

View File

@ -16,8 +16,7 @@
use crate::{commands::Command, context::Context}; use crate::{commands::Command, context::Context};
use leo_errors::Result; use leo_errors::Result;
use leo_package::build::BuildDirectory; use leo_package::{build::BuildDirectory, outputs::OutputsDirectory};
use leo_package::outputs::OutputsDirectory;
use clap::StructOpt; use clap::StructOpt;
use colored::Colorize; use colored::Colorize;

View File

@ -14,8 +14,10 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::commands::ALEO_CLI_COMMAND; use crate::{
use crate::{commands::Command, context::Context}; commands::{Command, ALEO_CLI_COMMAND},
context::Context,
};
use leo_errors::{CliError, PackageError, Result}; use leo_errors::{CliError, PackageError, Result};
use leo_package::build::BuildDirectory; use leo_package::build::BuildDirectory;

View File

@ -14,14 +14,12 @@
// You should have received a copy of the GNU General Public License // 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/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use crate::commands::Network;
use crate::{ use crate::{
commands::{Command, ALEO_CLI_COMMAND}, commands::{Command, Network, ALEO_CLI_COMMAND},
context::Context, context::Context,
}; };
use leo_errors::{CliError, PackageError, Result}; use leo_errors::{CliError, PackageError, Result};
use leo_package::build::BUILD_DIRECTORY_NAME; use leo_package::{build::BUILD_DIRECTORY_NAME, package::Package};
use leo_package::package::Package;
use snarkvm::file::AleoFile; use snarkvm::file::AleoFile;
use aleo::commands::New as AleoNew; use aleo::commands::New as AleoNew;
@ -97,9 +95,7 @@ impl Command for New {
aleo_file_path.push(AleoFile::<Network>::main_file_name()); aleo_file_path.push(AleoFile::<Network>::main_file_name());
// Remove the Aleo file from the package directory. // Remove the Aleo file from the package directory.
aleo_file aleo_file.remove(&aleo_file_path).map_err(PackageError::failed_to_remove_aleo_file)?;
.remove(&aleo_file_path)
.map_err(PackageError::failed_to_remove_aleo_file)?;
Ok(()) Ok(())
} }

View File

@ -15,9 +15,8 @@
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>. // along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
use super::build::BuildOptions; use super::build::BuildOptions;
use crate::commands::ALEO_CLI_COMMAND;
use crate::{ use crate::{
commands::{Build, Command}, commands::{Build, Command, ALEO_CLI_COMMAND},
context::Context, context::Context,
}; };
use leo_errors::{CliError, PackageError, Result}; use leo_errors::{CliError, PackageError, Result};
@ -34,10 +33,7 @@ pub struct Run {
#[structopt(name = "NAME", help = "The name of the program to run.", default_value = "main")] #[structopt(name = "NAME", help = "The name of the program to run.", default_value = "main")]
name: String, name: String,
#[structopt( #[structopt(name = "INPUTS", help = "The inputs to the program. If none are provided, the input file is used.")]
name = "INPUTS",
help = "The inputs to the program. If none are provided, the input file is used."
)]
inputs: Vec<String>, inputs: Vec<String>,
#[structopt(flatten)] #[structopt(flatten)]
@ -53,10 +49,7 @@ impl Command for Run {
} }
fn prelude(&self, context: Context) -> Result<Self::Input> { fn prelude(&self, context: Context) -> Result<Self::Input> {
(Build { (Build { options: self.compiler_options.clone() }).execute(context)
options: self.compiler_options.clone(),
})
.execute(context)
} }
fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output> { fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output> {

View File

@ -19,10 +19,10 @@ use leo_errors::{CliError, PackageError, Result};
use snarkvm::file::Manifest; use snarkvm::file::Manifest;
use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME}; use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME};
use std::fs::File;
use std::io::Write;
use std::{ use std::{
env::current_dir, env::current_dir,
fs::File,
io::Write,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };

View File

@ -125,10 +125,7 @@ impl<F, T> Format<F, T> {
/// ///
/// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html /// [thread ID]: https://doc.rust-lang.org/stable/std/thread/struct.ThreadId.html
pub fn with_thread_ids(self, display_thread_id: bool) -> Format<F, T> { pub fn with_thread_ids(self, display_thread_id: bool) -> Format<F, T> {
Format { Format { display_thread_id, ..self }
display_thread_id,
..self
}
} }
/// Sets whether or not the [name] of the current thread is displayed /// Sets whether or not the [name] of the current thread is displayed
@ -136,10 +133,7 @@ impl<F, T> Format<F, T> {
/// ///
/// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads /// [name]: https://doc.rust-lang.org/stable/std/thread/index.html#naming-threads
pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> { pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> {
Format { Format { display_thread_name, ..self }
display_thread_name,
..self
}
} }
} }

View File

@ -19,14 +19,12 @@ pub mod context;
pub mod logger; pub mod logger;
pub mod updater; pub mod updater;
use crate::commands::*; use crate::{commands::*, context::*};
use crate::context::*;
use leo_errors::Result; use leo_errors::Result;
use leo_span::symbol::create_session_if_not_set_then; use leo_span::symbol::create_session_if_not_set_then;
use clap::StructOpt; use clap::StructOpt;
use std::path::PathBuf; use std::{path::PathBuf, process::exit};
use std::process::exit;
/// CLI Arguments entry point - includes global parameters and subcommands /// CLI Arguments entry point - includes global parameters and subcommands
#[derive(StructOpt, Debug)] #[derive(StructOpt, Debug)]
@ -44,12 +42,7 @@ pub struct CLI {
#[structopt(help = "Custom Aleo PM backend URL", env = "APM_URL")] #[structopt(help = "Custom Aleo PM backend URL", env = "APM_URL")]
api: Option<String>, api: Option<String>,
#[structopt( #[structopt(long, global = true, help = "Optional path to Leo program root folder", parse(from_os_str))]
long,
global = true,
help = "Optional path to Leo program root folder",
parse(from_os_str)
)]
path: Option<PathBuf>, path: Option<PathBuf>,
} }
@ -95,15 +88,13 @@ fn set_panic_hook() {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
std::panic::set_hook({ std::panic::set_hook({
Box::new(move |e| { Box::new(move |e| {
eprintln!( eprintln!("thread `{}` {}", std::thread::current().name().unwrap_or("<unnamed>"), e);
"thread `{}` {}",
std::thread::current().name().unwrap_or("<unnamed>"),
e
);
eprintln!("stack backtrace: \n{:?}", backtrace::Backtrace::new()); eprintln!("stack backtrace: \n{:?}", backtrace::Backtrace::new());
eprintln!("error: internal compiler error: unexpected panic\n"); eprintln!("error: internal compiler error: unexpected panic\n");
eprintln!("note: the compiler unexpectedly panicked. this is a bug.\n"); eprintln!("note: the compiler unexpectedly panicked. this is a bug.\n");
eprintln!("note: we would appreciate a bug report: https://github.com/AleoHQ/leo/issues/new?labels=bug,panic&template=bug.md&title=[Bug]\n"); eprintln!(
"note: we would appreciate a bug report: https://github.com/AleoHQ/leo/issues/new?labels=bug,panic&template=bug.md&title=[Bug]\n"
);
eprintln!( eprintln!(
"note: {} {} running on {} {}\n", "note: {} {} running on {} {}\n",
env!("CARGO_PKG_NAME"), env!("CARGO_PKG_NAME"),
@ -111,10 +102,7 @@ fn set_panic_hook() {
sys_info::os_type().unwrap_or_else(|e| e.to_string()), sys_info::os_type().unwrap_or_else(|e| e.to_string()),
sys_info::os_release().unwrap_or_else(|e| e.to_string()), sys_info::os_release().unwrap_or_else(|e| e.to_string()),
); );
eprintln!( eprintln!("note: compiler args: {}\n", std::env::args().collect::<Vec<_>>().join(" "));
"note: compiler args: {}\n",
std::env::args().collect::<Vec<_>>().join(" ")
);
eprintln!("note: compiler flags: {:?}\n", CLI::parse()); eprintln!("note: compiler flags: {:?}\n", CLI::parse());
}) })
}); });
@ -134,13 +122,10 @@ pub fn handle_error<T>(res: Result<T>) -> T {
pub fn run_with_args(cli: CLI) -> Result<()> { pub fn run_with_args(cli: CLI) -> Result<()> {
if !cli.quiet { if !cli.quiet {
// Init logger with optional debug flag. // Init logger with optional debug flag.
logger::init_logger( logger::init_logger("leo", match cli.debug {
"leo", false => 1,
match cli.debug { true => 2,
false => 1, })?;
true => 2,
},
)?;
} }
// Get custom root folder and create context for it. // Get custom root folder and create context for it.

View File

@ -16,8 +16,11 @@
use leo_errors::{PackageError, Result}; use leo_errors::{PackageError, Result};
use std::path::PathBuf; use std::{
use std::{borrow::Cow, fs, path::Path}; borrow::Cow,
fs,
path::{Path, PathBuf},
};
pub static BUILD_DIRECTORY_NAME: &str = "build/"; pub static BUILD_DIRECTORY_NAME: &str = "build/";

View File

@ -17,8 +17,11 @@
use crate::parse_file_paths; use crate::parse_file_paths;
use leo_errors::{PackageError, Result}; use leo_errors::{PackageError, Result};
use std::path::PathBuf; use std::{
use std::{borrow::Cow, fs, path::Path}; borrow::Cow,
fs,
path::{Path, PathBuf},
};
pub static IMPORTS_DIRECTORY_NAME: &str = "imports/"; pub static IMPORTS_DIRECTORY_NAME: &str = "imports/";

View File

@ -24,7 +24,8 @@ use serde::Deserialize;
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::{ fs::{
File, {self}, File,
{self},
}, },
io::Write, io::Write,
path::Path, path::Path,
@ -39,9 +40,7 @@ pub struct InputFile {
impl InputFile { impl InputFile {
pub fn new(package_name: &str) -> Self { pub fn new(package_name: &str) -> Self {
Self { Self { package_name: package_name.to_string() }
package_name: package_name.to_string(),
}
} }
pub fn filename(&self) -> String { pub fn filename(&self) -> String {
@ -67,8 +66,7 @@ impl InputFile {
let path = self.setup_file_path(path); let path = self.setup_file_path(path);
let mut file = File::create(path).map_err(PackageError::io_error_input_file)?; let mut file = File::create(path).map_err(PackageError::io_error_input_file)?;
file.write_all(self.template().as_bytes()) file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_input_file)?;
.map_err(PackageError::io_error_input_file)?;
Ok(()) Ok(())
} }
@ -89,8 +87,7 @@ b: u32 = 2u32;
if !path.ends_with(INPUTS_DIRECTORY_NAME) { if !path.ends_with(INPUTS_DIRECTORY_NAME) {
path.to_mut().push(INPUTS_DIRECTORY_NAME); path.to_mut().push(INPUTS_DIRECTORY_NAME);
} }
path.to_mut() path.to_mut().push(format!("{}{INPUT_FILE_EXTENSION}", self.package_name));
.push(format!("{}{INPUT_FILE_EXTENSION}", self.package_name));
} }
path path
} }

View File

@ -27,8 +27,7 @@ pub mod source;
use leo_errors::{PackageError, Result}; use leo_errors::{PackageError, Result};
use std::fs::ReadDir; use std::{fs, fs::ReadDir, path::PathBuf};
use std::{fs, path::PathBuf};
pub static LEO_FILE_EXTENSION: &str = ".leo"; pub static LEO_FILE_EXTENSION: &str = ".leo";

View File

@ -33,16 +33,12 @@ pub enum Snapshot {
impl fmt::Display for Snapshot { impl fmt::Display for Snapshot {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!( write!(f, "{}", match self {
f, Self::Initial => "initial_ast",
"{}", Self::ImportsResolved => "imports_resolved_ast",
match self { Self::TypeInference => "type_inferenced_ast",
Self::Initial => "initial_ast", Self::Canonicalization => "canonicalization_ast",
Self::ImportsResolved => "imports_resolved_ast", })
Self::TypeInference => "type_inferenced_ast",
Self::Canonicalization => "canonicalization_ast",
}
)
} }
} }
@ -58,10 +54,7 @@ pub struct SnapshotFile {
impl SnapshotFile { impl SnapshotFile {
pub fn new(package_name: &str, snapshot: Snapshot) -> Self { pub fn new(package_name: &str, snapshot: Snapshot) -> Self {
Self { Self { package_name: package_name.to_string(), snapshot }
package_name: package_name.to_string(),
snapshot,
}
} }
pub fn exists_at(&self, path: &Path) -> bool { pub fn exists_at(&self, path: &Path) -> bool {
@ -97,8 +90,7 @@ impl SnapshotFile {
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.to_mut().push(OUTPUTS_DIRECTORY_NAME); path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
} }
path.to_mut() path.to_mut().push(format!("{}{AST_SNAPSHOT_FILE_EXTENSION}", self.snapshot));
.push(format!("{}{AST_SNAPSHOT_FILE_EXTENSION}", self.snapshot));
} }
path path
} }

View File

@ -23,7 +23,8 @@ use serde::Deserialize;
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::{ fs::{
File, {self}, File,
{self},
}, },
io::Write, io::Write,
path::Path, path::Path,
@ -38,9 +39,7 @@ pub struct ChecksumFile {
impl ChecksumFile { impl ChecksumFile {
pub fn new(package_name: &str) -> Self { pub fn new(package_name: &str) -> Self {
Self { Self { package_name: package_name.to_string() }
package_name: package_name.to_string(),
}
} }
pub fn exists_at(&self, path: &Path) -> bool { pub fn exists_at(&self, path: &Path) -> bool {
@ -62,8 +61,7 @@ impl ChecksumFile {
let path = self.setup_file_path(path); let path = self.setup_file_path(path);
let mut file = File::create(path).map_err(PackageError::io_error_checksum_file)?; let mut file = File::create(path).map_err(PackageError::io_error_checksum_file)?;
file.write_all(checksum.as_bytes()) file.write_all(checksum.as_bytes()).map_err(PackageError::io_error_checksum_file)?;
.map_err(PackageError::io_error_checksum_file)?;
Ok(()) Ok(())
} }
@ -85,8 +83,7 @@ impl ChecksumFile {
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.to_mut().push(OUTPUTS_DIRECTORY_NAME); path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
} }
path.to_mut() path.to_mut().push(format!("{}{CHECKSUM_FILE_EXTENSION}", self.package_name));
.push(format!("{}{CHECKSUM_FILE_EXTENSION}", self.package_name));
} }
path path
} }

View File

@ -23,7 +23,8 @@ use serde::Deserialize;
use std::{ use std::{
borrow::Cow, borrow::Cow,
fs::{ fs::{
File, {self}, File,
{self},
}, },
io::Write, io::Write,
path::Path, path::Path,
@ -38,9 +39,7 @@ pub struct CircuitFile {
impl CircuitFile { impl CircuitFile {
pub fn new(package_name: &str) -> Self { pub fn new(package_name: &str) -> Self {
Self { Self { package_name: package_name.to_string() }
package_name: package_name.to_string(),
}
} }
pub fn exists_at(&self, path: &Path) -> bool { pub fn exists_at(&self, path: &Path) -> bool {
@ -62,8 +61,7 @@ impl CircuitFile {
let path = self.setup_file_path(path); let path = self.setup_file_path(path);
let mut file = File::create(path).map_err(PackageError::io_error_circuit_file)?; let mut file = File::create(path).map_err(PackageError::io_error_circuit_file)?;
file.write_all(circuit.as_bytes()) file.write_all(circuit.as_bytes()).map_err(PackageError::io_error_circuit_file)?;
.map_err(PackageError::io_error_circuit_file)?;
Ok(()) Ok(())
} }
@ -85,8 +83,7 @@ impl CircuitFile {
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) { if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
path.to_mut().push(OUTPUTS_DIRECTORY_NAME); path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
} }
path.to_mut() path.to_mut().push(format!("{}{CIRCUIT_FILE_EXTENSION}", self.package_name));
.push(format!("{}{CIRCUIT_FILE_EXTENSION}", self.package_name));
} }
path path
} }

View File

@ -16,8 +16,11 @@
use leo_errors::{PackageError, Result}; use leo_errors::{PackageError, Result};
use std::path::PathBuf; use std::{
use std::{borrow::Cow, fs, path::Path}; borrow::Cow,
fs,
path::{Path, PathBuf},
};
pub static OUTPUTS_DIRECTORY_NAME: &str = "outputs/"; pub static OUTPUTS_DIRECTORY_NAME: &str = "outputs/";

View File

@ -41,12 +41,7 @@ impl Package {
return Err(PackageError::invalid_package_name(package_name).into()); return Err(PackageError::invalid_package_name(package_name).into());
} }
Ok(Self { Ok(Self { name: package_name.to_owned(), version: "0.1.0".to_owned(), description: None, license: None })
name: package_name.to_owned(),
version: "0.1.0".to_owned(),
description: None,
license: None,
})
} }
/// Returns `true` if the package name is valid. /// Returns `true` if the package name is valid.

View File

@ -46,8 +46,7 @@ impl Gitignore {
} }
let mut file = File::create(&path).map_err(PackageError::io_error_gitignore_file)?; let mut file = File::create(&path).map_err(PackageError::io_error_gitignore_file)?;
file.write_all(self.template().as_bytes()) file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_gitignore_file)?;
.map_err(PackageError::io_error_gitignore_file)?;
Ok(()) Ok(())
} }

View File

@ -31,9 +31,7 @@ pub struct MainFile {
impl MainFile { impl MainFile {
pub fn new(package_name: &str) -> Self { pub fn new(package_name: &str) -> Self {
Self { Self { package_name: package_name.to_string() }
package_name: package_name.to_string(),
}
} }
pub fn filename() -> String { pub fn filename() -> String {
@ -61,9 +59,7 @@ impl MainFile {
} }
let mut file = File::create(&path).map_err(PackageError::io_error_main_file)?; let mut file = File::create(&path).map_err(PackageError::io_error_main_file)?;
Ok(file Ok(file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_main_file)?)
.write_all(self.template().as_bytes())
.map_err(PackageError::io_error_main_file)?)
} }
// TODO: Generalize to other networks. // TODO: Generalize to other networks.

View File

@ -104,10 +104,7 @@ impl Sample {
/// Leverages the test-framework to grab all tests /// Leverages the test-framework to grab all tests
/// that are passing compiler tests or marked as benchmark tests. /// that are passing compiler tests or marked as benchmark tests.
fn load_samples() -> Vec<Self> { fn load_samples() -> Vec<Self> {
get_benches() get_benches().into_iter().map(|(name, input)| Self { name, input }).collect()
.into_iter()
.map(|(name, input)| Self { name, input })
.collect()
} }
fn data(&self) -> (&str, FileName) { fn data(&self) -> (&str, FileName) {
@ -147,9 +144,7 @@ impl Sample {
fn bencher_after_parse(&self, c: &mut Criterion, mode: &str, mut logic: impl FnMut(Compiler) -> Duration) { fn bencher_after_parse(&self, c: &mut Criterion, mode: &str, mut logic: impl FnMut(Compiler) -> Duration) {
self.bencher(c, mode, |mut compiler| { self.bencher(c, mode, |mut compiler| {
let (input, name) = self.data(); let (input, name) = self.data();
compiler compiler.parse_program_from_string(input, name).expect("Failed to parse program");
.parse_program_from_string(input, name)
.expect("Failed to parse program");
logic(compiler) logic(compiler)
}); });
} }
@ -189,9 +184,8 @@ impl Sample {
fn bench_loop_unroller(&self, c: &mut Criterion) { fn bench_loop_unroller(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "loop unrolling pass", |mut compiler| { self.bencher_after_parse(c, "loop unrolling pass", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, _struct_graph, _call_graph) = compiler let (symbol_table, _struct_graph, _call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.loop_unrolling_pass(symbol_table); let out = compiler.loop_unrolling_pass(symbol_table);
let time = start.elapsed(); let time = start.elapsed();
@ -203,12 +197,9 @@ impl Sample {
fn bench_ssa(&self, c: &mut Criterion) { fn bench_ssa(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "full", |mut compiler| { self.bencher_after_parse(c, "full", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, _struct_graph, _call_graph) = compiler let (symbol_table, _struct_graph, _call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler
.loop_unrolling_pass(symbol_table)
.expect("failed to run loop unrolling pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.static_single_assignment_pass(&symbol_table); let out = compiler.static_single_assignment_pass(&symbol_table);
let time = start.elapsed(); let time = start.elapsed();
@ -220,15 +211,10 @@ impl Sample {
fn bench_flattener(&self, c: &mut Criterion) { fn bench_flattener(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "flattener pass", |mut compiler| { self.bencher_after_parse(c, "flattener pass", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, _struct_graph, _call_graph) = compiler let (symbol_table, _struct_graph, _call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
.loop_unrolling_pass(symbol_table)
.expect("failed to run loop unrolling pass");
let assigner = compiler
.static_single_assignment_pass(&symbol_table)
.expect("failed to run ssa pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.flattening_pass(&symbol_table, assigner); let out = compiler.flattening_pass(&symbol_table, assigner);
let time = start.elapsed(); let time = start.elapsed();
@ -240,18 +226,11 @@ impl Sample {
fn bench_inline(&self, c: &mut Criterion) { fn bench_inline(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "inliner pass", |mut compiler| { self.bencher_after_parse(c, "inliner pass", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, _struct_graph, call_graph) = compiler let (symbol_table, _struct_graph, call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
.loop_unrolling_pass(symbol_table) let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
.expect("failed to run loop unrolling pass");
let assigner = compiler
.static_single_assignment_pass(&symbol_table)
.expect("failed to run ssa pass");
let assigner = compiler
.flattening_pass(&symbol_table, assigner)
.expect("failed to run flattener pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.function_inlining_pass(&call_graph, assigner); let out = compiler.function_inlining_pass(&call_graph, assigner);
let time = start.elapsed(); let time = start.elapsed();
@ -263,21 +242,12 @@ impl Sample {
fn bench_dce(&self, c: &mut Criterion) { fn bench_dce(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "inliner pass", |mut compiler| { self.bencher_after_parse(c, "inliner pass", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, _struct_graph, call_graph) = compiler let (symbol_table, _struct_graph, call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
.loop_unrolling_pass(symbol_table) let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
.expect("failed to run loop unrolling pass"); let _ = compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run inliner pass");
let assigner = compiler
.static_single_assignment_pass(&symbol_table)
.expect("failed to run ssa pass");
let assigner = compiler
.flattening_pass(&symbol_table, assigner)
.expect("failed to run flattener pass");
let _ = compiler
.function_inlining_pass(&call_graph, assigner)
.expect("failed to run inliner pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.dead_code_elimination_pass(); let out = compiler.dead_code_elimination_pass();
let time = start.elapsed(); let time = start.elapsed();
@ -289,21 +259,12 @@ impl Sample {
fn bench_codegen(&self, c: &mut Criterion) { fn bench_codegen(&self, c: &mut Criterion) {
self.bencher_after_parse(c, "inliner pass", |mut compiler| { self.bencher_after_parse(c, "inliner pass", |mut compiler| {
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, struct_graph, call_graph) = compiler let (symbol_table, struct_graph, call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
.loop_unrolling_pass(symbol_table) let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
.expect("failed to run loop unrolling pass"); let _ = compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run inliner pass");
let assigner = compiler
.static_single_assignment_pass(&symbol_table)
.expect("failed to run ssa pass");
let assigner = compiler
.flattening_pass(&symbol_table, assigner)
.expect("failed to run flattener pass");
let _ = compiler
.function_inlining_pass(&call_graph, assigner)
.expect("failed to run inliner pass");
compiler.dead_code_elimination_pass().expect("failed to run dce pass"); compiler.dead_code_elimination_pass().expect("failed to run dce pass");
let start = Instant::now(); let start = Instant::now();
let out = compiler.code_generation_pass(&symbol_table, &struct_graph, &call_graph); let out = compiler.code_generation_pass(&symbol_table, &struct_graph, &call_graph);
@ -317,25 +278,14 @@ impl Sample {
self.bencher(c, "full", |mut compiler| { self.bencher(c, "full", |mut compiler| {
let (input, name) = self.data(); let (input, name) = self.data();
let start = Instant::now(); let start = Instant::now();
compiler compiler.parse_program_from_string(input, name).expect("Failed to parse program");
.parse_program_from_string(input, name)
.expect("Failed to parse program");
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table"); let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
let (symbol_table, struct_graph, call_graph) = compiler let (symbol_table, struct_graph, call_graph) =
.type_checker_pass(symbol_table) compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
.expect("failed to run type check pass"); let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
let symbol_table = compiler let assigner = compiler.static_single_assignment_pass(&symbol_table).expect("failed to run ssa pass");
.loop_unrolling_pass(symbol_table) let assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattening pass");
.expect("failed to run loop unrolling pass"); compiler.function_inlining_pass(&call_graph, assigner).expect("failed to run function inlining pass");
let assigner = compiler
.static_single_assignment_pass(&symbol_table)
.expect("failed to run ssa pass");
let assigner = compiler
.flattening_pass(&symbol_table, assigner)
.expect("failed to run flattening pass");
compiler
.function_inlining_pass(&call_graph, assigner)
.expect("failed to run function inlining pass");
compiler.dead_code_elimination_pass().expect("failed to run dce pass"); compiler.dead_code_elimination_pass().expect("failed to run dce pass");
compiler compiler
.code_generation_pass(&symbol_table, &struct_graph, &call_graph) .code_generation_pass(&symbol_table, &struct_graph, &call_graph)

View File

@ -27,32 +27,11 @@ pub struct TestFailure {
#[derive(Debug)] #[derive(Debug)]
pub enum TestError { pub enum TestError {
Panicked { Panicked { test: String, index: usize, error: String },
test: String, UnexpectedOutput { test: String, index: usize, expected: Value, output: Value },
index: usize, PassedAndShouldntHave { test: String, index: usize },
error: String, FailedAndShouldntHave { test: String, index: usize, error: String },
}, UnexpectedError { test: String, index: usize, expected: String, output: String },
UnexpectedOutput {
test: String,
index: usize,
expected: Value,
output: Value,
},
PassedAndShouldntHave {
test: String,
index: usize,
},
FailedAndShouldntHave {
test: String,
index: usize,
error: String,
},
UnexpectedError {
test: String,
index: usize,
expected: String,
output: String,
},
MismatchedTestExpectationLength, MismatchedTestExpectationLength,
MissingTestConfig, MissingTestConfig,
} }
@ -60,28 +39,13 @@ pub enum TestError {
impl fmt::Display for TestError { impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let format_test = |test: &str| -> String { let format_test = |test: &str| -> String {
if test.len() > 50 { if test.len() > 50 { String::new() } else { format!("\n\n{test}\n\n") }
String::new()
} else {
format!("\n\n{test}\n\n")
}
}; };
match self { match self {
TestError::Panicked { test, index, error } => { TestError::Panicked { test, index, error } => {
write!( write!(f, "test #{}: {}encountered a rust panic:\n{}", index + 1, format_test(test), error)
f,
"test #{}: {}encountered a rust panic:\n{}",
index + 1,
format_test(test),
error
)
} }
TestError::UnexpectedOutput { TestError::UnexpectedOutput { test, index, expected, output } => {
test,
index,
expected,
output,
} => {
write!( write!(
f, f,
"test #{}: {}expected\n{}\ngot\n{}", "test #{}: {}expected\n{}\ngot\n{}",
@ -95,28 +59,10 @@ impl fmt::Display for TestError {
write!(f, "test #{}: {}passed and shouldn't have", index + 1, format_test(test)) write!(f, "test #{}: {}passed and shouldn't have", index + 1, format_test(test))
} }
TestError::FailedAndShouldntHave { test, index, error } => { TestError::FailedAndShouldntHave { test, index, error } => {
write!( write!(f, "test #{}: {}failed and shouldn't have:\n{}", index + 1, format_test(test), error)
f,
"test #{}: {}failed and shouldn't have:\n{}",
index + 1,
format_test(test),
error
)
} }
TestError::UnexpectedError { TestError::UnexpectedError { test, expected, output, index } => {
test, write!(f, "test #{}: {}expected error\n{}\ngot\n{}", index + 1, format_test(test), expected, output)
expected,
output,
index,
} => {
write!(
f,
"test #{}: {}expected error\n{}\ngot\n{}",
index + 1,
format_test(test),
expected,
output
)
} }
TestError::MismatchedTestExpectationLength => write!(f, "invalid number of test expectations"), TestError::MismatchedTestExpectationLength => write!(f, "invalid number of test expectations"),
TestError::MissingTestConfig => write!(f, "missing test config"), TestError::MissingTestConfig => write!(f, "missing test config"),
@ -132,11 +78,7 @@ pub fn emit_errors(
test_index: usize, test_index: usize,
) -> Option<TestError> { ) -> Option<TestError> {
match (output, mode) { match (output, mode) {
(Err(e), _) => Some(TestError::Panicked { (Err(e), _) => Some(TestError::Panicked { test: test.to_string(), index: test_index, error: e.to_string() }),
test: test.to_string(),
index: test_index,
error: e.to_string(),
}),
(Ok(Ok(output)), TestExpectationMode::Pass) => { (Ok(Ok(output)), TestExpectationMode::Pass) => {
// passed and should have // passed and should have
if let Some(expected_output) = expected_output.as_ref() { if let Some(expected_output) = expected_output.as_ref() {
@ -152,15 +94,12 @@ pub fn emit_errors(
} }
None None
} }
(Ok(Ok(_tokens)), TestExpectationMode::Fail) => Some(TestError::PassedAndShouldntHave { (Ok(Ok(_tokens)), TestExpectationMode::Fail) => {
test: test.to_string(), Some(TestError::PassedAndShouldntHave { test: test.to_string(), index: test_index })
index: test_index, }
}), (Ok(Err(err)), TestExpectationMode::Pass) => {
(Ok(Err(err)), TestExpectationMode::Pass) => Some(TestError::FailedAndShouldntHave { Some(TestError::FailedAndShouldntHave { test: test.to_string(), error: err.to_string(), index: test_index })
test: test.to_string(), }
error: err.to_string(),
index: test_index,
}),
(Ok(Err(err)), TestExpectationMode::Fail) => { (Ok(Err(err)), TestExpectationMode::Fail) => {
let expected_output: Option<String> = let expected_output: Option<String> =
expected_output.map(|x| serde_yaml::from_value(x).expect("test expectation deserialize failed")); expected_output.map(|x| serde_yaml::from_value(x).expect("test expectation deserialize failed"));

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