mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-12-22 17:51:39 +03:00
Fmts and clippies
This commit is contained in:
parent
47e81a5d15
commit
8adc6c76b8
13
build.rs
13
build.rs
@ -26,17 +26,8 @@ use walkdir::WalkDir;
|
||||
const EXPECTED_LICENSE_TEXT: &str = include_str!(".resources/license_header");
|
||||
|
||||
// The following directories will be excluded from the license scan.
|
||||
const DIRS_TO_SKIP: [&str; 9] = [
|
||||
".cargo",
|
||||
".circleci",
|
||||
".git",
|
||||
".github",
|
||||
".resources",
|
||||
"docs",
|
||||
"examples",
|
||||
"target",
|
||||
"tests",
|
||||
];
|
||||
const DIRS_TO_SKIP: [&str; 9] =
|
||||
[".cargo", ".circleci", ".git", ".github", ".resources", "docs", "examples", "target", "tests"];
|
||||
|
||||
fn compare_license_text(path: &Path, expected_lines: &[&str]) {
|
||||
let file = File::open(path).unwrap();
|
||||
|
@ -29,10 +29,7 @@ pub fn serialize<S: Serializer>(
|
||||
let joined: IndexMap<String, DefinitionStatement> = global_consts
|
||||
.into_iter()
|
||||
.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();
|
||||
|
||||
@ -47,10 +44,7 @@ pub fn deserialize<'de, D: Deserializer<'de>>(
|
||||
.map(|(name, program)| {
|
||||
(
|
||||
name.split(',')
|
||||
.map(|ident_name| Identifier {
|
||||
name: Symbol::intern(ident_name),
|
||||
span: Default::default(),
|
||||
})
|
||||
.map(|ident_name| Identifier { name: Symbol::intern(ident_name), span: Default::default() })
|
||||
.collect::<Vec<Identifier>>(),
|
||||
program,
|
||||
)
|
||||
|
@ -20,9 +20,13 @@ use leo_span::{Span, Symbol};
|
||||
use crate::{simple_node_impl, Node};
|
||||
use serde::{
|
||||
de::{
|
||||
Visitor, {self},
|
||||
Visitor,
|
||||
{self},
|
||||
},
|
||||
Deserialize, Deserializer, Serialize, Serializer,
|
||||
Deserialize,
|
||||
Deserializer,
|
||||
Serialize,
|
||||
Serializer,
|
||||
};
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
@ -48,10 +52,7 @@ simple_node_impl!(Identifier);
|
||||
impl Identifier {
|
||||
/// Constructs a new identifier with `name` and a default span.
|
||||
pub fn new(name: Symbol) -> Self {
|
||||
Self {
|
||||
name,
|
||||
span: Span::default(),
|
||||
}
|
||||
Self { name, span: Span::default() }
|
||||
}
|
||||
|
||||
/// Check if the Identifier name matches the other name.
|
||||
|
@ -30,10 +30,7 @@ pub fn serialize<S: Serializer>(
|
||||
imported_modules
|
||||
.into_iter()
|
||||
.map(|(package, program)| {
|
||||
let package = package
|
||||
.iter()
|
||||
.map(|x| x.as_str(s, |s| s.to_owned()))
|
||||
.collect::<Vec<_>>();
|
||||
let package = package.iter().map(|x| x.as_str(s, |s| s.to_owned())).collect::<Vec<_>>();
|
||||
(package.join("."), program.clone())
|
||||
})
|
||||
.collect()
|
||||
|
@ -15,8 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
/// A number string guaranteed to be positive.
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -86,42 +86,38 @@ pub enum BinaryOperation {
|
||||
|
||||
impl fmt::Display for BinaryOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Add => "+",
|
||||
Self::AddWrapped => "add_wrapped",
|
||||
Self::And => "&&",
|
||||
Self::BitwiseAnd => "&",
|
||||
Self::Div => "/",
|
||||
Self::DivWrapped => "div_wrapped",
|
||||
Self::Eq => "==",
|
||||
Self::Gte => ">=",
|
||||
Self::Gt => ">",
|
||||
Self::Lte => "<=",
|
||||
Self::Lt => "<",
|
||||
Self::Mod => "mod",
|
||||
Self::Mul => "*",
|
||||
Self::MulWrapped => "mul_wrapped",
|
||||
Self::Nand => "NAND",
|
||||
Self::Neq => "!=",
|
||||
Self::Nor => "NOR",
|
||||
Self::Or => "||",
|
||||
Self::BitwiseOr => "|",
|
||||
Self::Pow => "**",
|
||||
Self::PowWrapped => "pow_wrapped",
|
||||
Self::Rem => "%",
|
||||
Self::RemWrapped => "rem_wrapped",
|
||||
Self::Shl => "<<",
|
||||
Self::ShlWrapped => "shl_wrapped",
|
||||
Self::Shr => ">>",
|
||||
Self::ShrWrapped => "shr_wrapped",
|
||||
Self::Sub => "-",
|
||||
Self::SubWrapped => "sub_wrapped",
|
||||
Self::Xor => "^",
|
||||
}
|
||||
)
|
||||
write!(f, "{}", match self {
|
||||
Self::Add => "+",
|
||||
Self::AddWrapped => "add_wrapped",
|
||||
Self::And => "&&",
|
||||
Self::BitwiseAnd => "&",
|
||||
Self::Div => "/",
|
||||
Self::DivWrapped => "div_wrapped",
|
||||
Self::Eq => "==",
|
||||
Self::Gte => ">=",
|
||||
Self::Gt => ">",
|
||||
Self::Lte => "<=",
|
||||
Self::Lt => "<",
|
||||
Self::Mod => "mod",
|
||||
Self::Mul => "*",
|
||||
Self::MulWrapped => "mul_wrapped",
|
||||
Self::Nand => "NAND",
|
||||
Self::Neq => "!=",
|
||||
Self::Nor => "NOR",
|
||||
Self::Or => "||",
|
||||
Self::BitwiseOr => "|",
|
||||
Self::Pow => "**",
|
||||
Self::PowWrapped => "pow_wrapped",
|
||||
Self::Rem => "%",
|
||||
Self::RemWrapped => "rem_wrapped",
|
||||
Self::Shl => "<<",
|
||||
Self::ShlWrapped => "shl_wrapped",
|
||||
Self::Shr => ">>",
|
||||
Self::ShrWrapped => "shr_wrapped",
|
||||
Self::Sub => "-",
|
||||
Self::SubWrapped => "sub_wrapped",
|
||||
Self::Xor => "^",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,15 +82,7 @@ impl StructExpression {
|
||||
|
||||
impl fmt::Display for StructExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{{{}}}",
|
||||
self.members
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
write!(f, "{{{}}}", self.members.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,15 +30,7 @@ pub struct TupleExpression {
|
||||
|
||||
impl fmt::Display for TupleExpression {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"({})",
|
||||
self.elements
|
||||
.iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",")
|
||||
)
|
||||
write!(f, "({})", self.elements.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,11 +41,7 @@ impl External {
|
||||
|
||||
impl fmt::Display for External {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}: {}.leo/{}.record",
|
||||
self.identifier, self.program_name, self.record
|
||||
)
|
||||
write!(f, "{}: {}.leo/{}.record", self.identifier, self.program_name, self.record)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,14 +47,7 @@ impl Finalize {
|
||||
_ => Type::Tuple(Tuple(output.iter().map(|output| output.type_()).collect())),
|
||||
};
|
||||
|
||||
Self {
|
||||
identifier,
|
||||
input,
|
||||
output,
|
||||
output_type,
|
||||
block,
|
||||
span,
|
||||
}
|
||||
Self { identifier, input, output, output_type, block, span }
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,16 +57,9 @@ impl fmt::Display for Finalize {
|
||||
let returns = match self.output.len() {
|
||||
0 => "()".to_string(),
|
||||
1 => self.output[0].to_string(),
|
||||
_ => format!(
|
||||
"({})",
|
||||
self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
|
||||
),
|
||||
_ => format!("({})", self.output.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")),
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
" finalize {}({parameters}) -> {returns} {}",
|
||||
self.identifier, self.block
|
||||
)
|
||||
write!(f, " finalize {}({parameters}) -> {returns} {}", self.identifier, self.block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,18 +97,9 @@ impl Function {
|
||||
_ => Type::Tuple(Tuple(output.iter().map(|output| get_output_type(output)).collect())),
|
||||
};
|
||||
|
||||
Function {
|
||||
annotations,
|
||||
variant,
|
||||
identifier,
|
||||
input,
|
||||
output,
|
||||
output_type,
|
||||
block,
|
||||
finalize,
|
||||
span,
|
||||
}
|
||||
Function { annotations, variant, identifier, input, output, output_type, block, finalize, span }
|
||||
}
|
||||
|
||||
/// Returns function name.
|
||||
pub fn name(&self) -> Symbol {
|
||||
self.identifier.name
|
||||
|
@ -31,6 +31,7 @@ pub enum InputValue {
|
||||
|
||||
impl TryFrom<(Type, Expression)> for InputValue {
|
||||
type Error = LeoError;
|
||||
|
||||
fn try_from(value: (Type, Expression)) -> Result<Self> {
|
||||
Ok(match value {
|
||||
(type_, Expression::Literal(lit)) => match (type_, lit) {
|
||||
|
@ -24,6 +24,7 @@ pub struct ProgramInput {
|
||||
|
||||
impl TryFrom<InputAst> for ProgramInput {
|
||||
type Error = LeoError;
|
||||
|
||||
fn try_from(input: InputAst) -> Result<Self> {
|
||||
let mut main = IndexMap::new();
|
||||
|
||||
@ -34,10 +35,7 @@ impl TryFrom<InputAst> for ProgramInput {
|
||||
};
|
||||
|
||||
for definition in section.definitions {
|
||||
target.insert(
|
||||
definition.name.name,
|
||||
InputValue::try_from((definition.type_, definition.value))?,
|
||||
);
|
||||
target.insert(definition.name.name, InputValue::try_from((definition.type_, definition.value))?);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
match value {
|
||||
serde_json::Value::Object(map) => serde_json::Value::Object(
|
||||
map.into_iter()
|
||||
.filter(|(k, _)| k != key)
|
||||
.map(|(k, v)| (k, remove_key_from_json(v, key)))
|
||||
.collect(),
|
||||
map.into_iter().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.into_iter().map(|v| remove_key_from_json(v, key)).collect())
|
||||
|
@ -36,11 +36,7 @@ pub struct Mapping {
|
||||
|
||||
impl fmt::Display for Mapping {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"mapping {}: {} => {}",
|
||||
self.identifier, self.key_type, self.value_type
|
||||
)
|
||||
write!(f, "mapping {}: {} => {}", self.identifier, self.key_type, self.value_type)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,11 +47,7 @@ pub trait ExpressionReconstructor {
|
||||
AccessExpression::AssociatedFunction(AssociatedFunction {
|
||||
ty: function.ty,
|
||||
name: function.name,
|
||||
args: function
|
||||
.args
|
||||
.into_iter()
|
||||
.map(|arg| self.reconstruct_expression(arg).0)
|
||||
.collect(),
|
||||
args: function.args.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
|
||||
span: function.span,
|
||||
})
|
||||
}
|
||||
@ -87,11 +83,7 @@ pub trait ExpressionReconstructor {
|
||||
(
|
||||
Expression::Call(CallExpression {
|
||||
function: Box::new(self.reconstruct_expression(*input.function).0),
|
||||
arguments: input
|
||||
.arguments
|
||||
.into_iter()
|
||||
.map(|arg| self.reconstruct_expression(arg).0)
|
||||
.collect(),
|
||||
arguments: input.arguments.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
|
||||
external: input.external,
|
||||
span: input.span,
|
||||
}),
|
||||
@ -130,11 +122,7 @@ pub trait ExpressionReconstructor {
|
||||
fn reconstruct_tuple(&mut self, input: TupleExpression) -> (Expression, Self::AdditionalOutput) {
|
||||
(
|
||||
Expression::Tuple(TupleExpression {
|
||||
elements: input
|
||||
.elements
|
||||
.into_iter()
|
||||
.map(|element| self.reconstruct_expression(element).0)
|
||||
.collect(),
|
||||
elements: input.elements.into_iter().map(|element| self.reconstruct_expression(element).0).collect(),
|
||||
span: input.span,
|
||||
}),
|
||||
Default::default(),
|
||||
@ -212,11 +200,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
|
||||
fn reconstruct_block(&mut self, input: Block) -> (Block, Self::AdditionalOutput) {
|
||||
(
|
||||
Block {
|
||||
statements: input
|
||||
.statements
|
||||
.into_iter()
|
||||
.map(|s| self.reconstruct_statement(s).0)
|
||||
.collect(),
|
||||
statements: input.statements.into_iter().map(|s| self.reconstruct_statement(s).0).collect(),
|
||||
span: input.span,
|
||||
},
|
||||
Default::default(),
|
||||
@ -326,10 +310,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
|
||||
Statement::Return(ReturnStatement {
|
||||
expression: self.reconstruct_expression(input.expression).0,
|
||||
finalize_arguments: input.finalize_arguments.map(|arguments| {
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|argument| self.reconstruct_expression(argument).0)
|
||||
.collect()
|
||||
arguments.into_iter().map(|argument| self.reconstruct_expression(argument).0).collect()
|
||||
}),
|
||||
span: input.span,
|
||||
}),
|
||||
@ -358,21 +339,9 @@ pub trait ProgramReconstructor: StatementReconstructor {
|
||||
fn reconstruct_program_scope(&mut self, input: ProgramScope) -> ProgramScope {
|
||||
ProgramScope {
|
||||
program_id: input.program_id,
|
||||
structs: input
|
||||
.structs
|
||||
.into_iter()
|
||||
.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(),
|
||||
structs: input.structs.into_iter().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,
|
||||
}
|
||||
}
|
||||
|
@ -214,10 +214,7 @@ pub trait ProgramVisitor<'a>: StatementVisitor<'a> {
|
||||
fn visit_program(&mut self, input: &'a Program) {
|
||||
input.imports.values().for_each(|import| self.visit_import(&import.0));
|
||||
|
||||
input
|
||||
.program_scopes
|
||||
.values()
|
||||
.for_each(|scope| self.visit_program_scope(scope));
|
||||
input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
|
||||
}
|
||||
|
||||
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
|
||||
.functions
|
||||
.values()
|
||||
.for_each(|function| self.visit_function(function));
|
||||
input.functions.values().for_each(|function| self.visit_function(function));
|
||||
}
|
||||
|
||||
fn visit_import(&mut self, input: &'a Program) {
|
||||
|
@ -53,9 +53,6 @@ impl fmt::Display for Program {
|
||||
impl Default for Program {
|
||||
/// Constructs an empty program node.
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
imports: IndexMap::new(),
|
||||
program_scopes: IndexMap::new(),
|
||||
}
|
||||
Self { imports: IndexMap::new(), program_scopes: IndexMap::new() }
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
use crate::Identifier;
|
||||
|
||||
use core::fmt;
|
||||
use serde::de::Visitor;
|
||||
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde::{de, de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// An identifier for a program that is eventually deployed to the network.
|
||||
|
@ -35,9 +35,7 @@ impl fmt::Display for Block {
|
||||
if self.statements.is_empty() {
|
||||
writeln!(f, "\t")?;
|
||||
} else {
|
||||
self.statements
|
||||
.iter()
|
||||
.try_for_each(|statement| writeln!(f, "\t{statement}"))?;
|
||||
self.statements.iter().try_for_each(|statement| writeln!(f, "\t{statement}"))?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
|
@ -19,8 +19,7 @@ use crate::{Block, Expression, Identifier, Node, Type, Value};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::{cell::RefCell, fmt};
|
||||
|
||||
/// A bounded `for` loop statement `for variable in start .. =? stop block`.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
|
||||
@ -51,11 +50,7 @@ pub struct IterationStatement {
|
||||
impl fmt::Display for IterationStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let eq = if self.inclusive { "=" } else { "" };
|
||||
write!(
|
||||
f,
|
||||
"for {} in {}..{eq}{} {}",
|
||||
self.variable, self.start, self.stop, self.block
|
||||
)
|
||||
write!(f, "for {} in {}..{eq}{} {}", self.variable, self.start, self.stop, self.block)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,7 @@ pub enum Statement {
|
||||
impl Statement {
|
||||
/// Returns a dummy statement made from an empty block `{}`.
|
||||
pub fn dummy(span: Span) -> Self {
|
||||
Self::Block(Block {
|
||||
statements: Vec::new(),
|
||||
span,
|
||||
})
|
||||
Self::Block(Block { statements: Vec::new(), span })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,6 @@ impl Deref for Tuple {
|
||||
|
||||
impl fmt::Display for Tuple {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"({})",
|
||||
self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(",")
|
||||
)
|
||||
write!(f, "({})", self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(","))
|
||||
}
|
||||
}
|
||||
|
@ -70,10 +70,9 @@ impl Type {
|
||||
(Type::Mapping(left), Type::Mapping(right)) => {
|
||||
left.key.eq_flat(&right.key) && left.value.eq_flat(&right.value)
|
||||
}
|
||||
(Type::Tuple(left), Type::Tuple(right)) if left.len() == right.len() => left
|
||||
.iter()
|
||||
.zip_eq(right.iter())
|
||||
.all(|(left_type, right_type)| left_type.eq_flat(right_type)),
|
||||
(Type::Tuple(left), Type::Tuple(right)) if left.len() == right.len() => {
|
||||
left.iter().zip_eq(right.iter()).all(|(left_type, right_type)| left_type.eq_flat(right_type))
|
||||
}
|
||||
(Type::Identifier(left), Type::Identifier(right)) => left.matches(right),
|
||||
_ => false,
|
||||
}
|
||||
|
@ -201,26 +201,6 @@ pub enum 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!(
|
||||
@overflowing
|
||||
name: abs,
|
||||
@ -720,6 +700,26 @@ impl Value {
|
||||
[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 {
|
||||
|
@ -19,16 +19,13 @@
|
||||
//! The [`Compiler`] type compiles Leo programs into R1CS circuits.
|
||||
use leo_ast::Program;
|
||||
pub use leo_ast::{Ast, InputAst};
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_errors::{CompilerError, Result};
|
||||
use leo_errors::{emitter::Handler, CompilerError, Result};
|
||||
pub use leo_passes::SymbolTable;
|
||||
use leo_passes::*;
|
||||
use leo_span::source_map::FileName;
|
||||
use leo_span::symbol::with_session_globals;
|
||||
use leo_span::{source_map::FileName, symbol::with_session_globals};
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::{fs, path::PathBuf};
|
||||
|
||||
use crate::CompilerOptions;
|
||||
|
||||
@ -273,10 +270,7 @@ impl<'a> Compiler<'a> {
|
||||
fn write_ast_to_json(&self, file_suffix: &str) -> Result<()> {
|
||||
// Remove `Span`s if they are not enabled.
|
||||
if self.compiler_options.spans_enabled {
|
||||
self.ast.to_json_file(
|
||||
self.output_directory.clone(),
|
||||
&format!("{}.{file_suffix}", self.program_name),
|
||||
)?;
|
||||
self.ast.to_json_file(self.output_directory.clone(), &format!("{}.{file_suffix}", self.program_name))?;
|
||||
} else {
|
||||
self.ast.to_json_file_without_keys(
|
||||
self.output_directory.clone(),
|
||||
|
@ -29,8 +29,7 @@ use snarkvm::prelude::*;
|
||||
use crate::utilities::{get_cwd_option, hash_asts, hash_content, setup_build_directory};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Value;
|
||||
use std::rc::Rc;
|
||||
use std::{fs, path::Path};
|
||||
use std::{fs, path::Path, rc::Rc};
|
||||
|
||||
struct CompileNamespace;
|
||||
|
||||
|
@ -15,8 +15,16 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
mod utilities;
|
||||
use utilities::{buffer_if_err, compile_and_process, parse_program, BufferEmitter};
|
||||
use utilities::{get_cwd_option, setup_build_directory, Aleo, Network};
|
||||
use utilities::{
|
||||
buffer_if_err,
|
||||
compile_and_process,
|
||||
get_cwd_option,
|
||||
parse_program,
|
||||
setup_build_directory,
|
||||
Aleo,
|
||||
BufferEmitter,
|
||||
Network,
|
||||
};
|
||||
|
||||
use crate::utilities::{hash_asts, hash_content};
|
||||
|
||||
@ -27,15 +35,13 @@ use leo_test_framework::{
|
||||
Test,
|
||||
};
|
||||
|
||||
use snarkvm::console;
|
||||
use snarkvm::prelude::*;
|
||||
use snarkvm::{console, prelude::*};
|
||||
|
||||
use leo_test_framework::test::TestExpectationMode;
|
||||
use regex::Regex;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Value;
|
||||
use std::collections::BTreeMap;
|
||||
use std::{fs, path::Path, rc::Rc};
|
||||
use std::{collections::BTreeMap, fs, path::Path, rc::Rc};
|
||||
|
||||
// TODO: Evaluate namespace.
|
||||
struct ExecuteNamespace;
|
||||
@ -69,10 +75,7 @@ struct ExecuteOutput {
|
||||
fn run_test(test: Test, handler: &Handler, err_buf: &BufferEmitter) -> Result<Value, ()> {
|
||||
// Check that config expectation is always pass.
|
||||
if test.config.expectation != TestExpectationMode::Pass {
|
||||
buffer_if_err(
|
||||
err_buf,
|
||||
Err("Test expectation must be `Pass` for `Execute` tests.".to_string()),
|
||||
)?;
|
||||
buffer_if_err(err_buf, Err("Test expectation must be `Pass` for `Execute` tests.".to_string()))?;
|
||||
}
|
||||
|
||||
// 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))?;
|
||||
|
||||
// Extract the cases from the test config.
|
||||
let all_cases = test
|
||||
.config
|
||||
.extra
|
||||
.get("cases")
|
||||
.expect("An `Execute` config must have a `cases` field.")
|
||||
.as_mapping()
|
||||
.unwrap();
|
||||
let all_cases =
|
||||
test.config.extra.get("cases").expect("An `Execute` config must have a `cases` field.").as_mapping().unwrap();
|
||||
|
||||
// Initialize a map for the expected results.
|
||||
let mut results = BTreeMap::new();
|
||||
|
@ -17,7 +17,8 @@
|
||||
use leo_compiler::{Compiler, CompilerOptions};
|
||||
use leo_errors::{
|
||||
emitter::{Buffer, Emitter, Handler},
|
||||
LeoError, LeoWarning,
|
||||
LeoError,
|
||||
LeoWarning,
|
||||
};
|
||||
use leo_passes::{CodeGenerator, Pass};
|
||||
use leo_span::source_map::FileName;
|
||||
@ -25,12 +26,11 @@ use leo_test_framework::Test;
|
||||
|
||||
use snarkvm::prelude::*;
|
||||
|
||||
use snarkvm::file::Manifest;
|
||||
use snarkvm::package::Package;
|
||||
use std::fs::File;
|
||||
use snarkvm::{file::Manifest, package::Package};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fs,
|
||||
fs::File,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
@ -152,10 +152,7 @@ impl Display for LeoOrString {
|
||||
|
||||
/// A buffer used to emit errors into.
|
||||
#[derive(Clone)]
|
||||
pub struct BufferEmitter(
|
||||
pub Rc<RefCell<Buffer<LeoOrString>>>,
|
||||
pub Rc<RefCell<Buffer<LeoWarning>>>,
|
||||
);
|
||||
pub struct BufferEmitter(pub Rc<RefCell<Buffer<LeoOrString>>>, pub Rc<RefCell<Buffer<LeoWarning>>>);
|
||||
|
||||
impl Emitter for BufferEmitter {
|
||||
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 {
|
||||
tempfile::tempdir()
|
||||
.expect("Failed to open temporary directory")
|
||||
.into_path()
|
||||
tempfile::tempdir().expect("Failed to open temporary directory").into_path()
|
||||
}
|
||||
|
||||
pub fn compile_and_process<'a>(parsed: &'a mut Compiler<'a>) -> Result<String, LeoError> {
|
||||
|
@ -26,10 +26,7 @@ use std::{
|
||||
};
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(
|
||||
name = "input parser",
|
||||
about = "Parse an Input file and save its JSON representation"
|
||||
)]
|
||||
#[structopt(name = "input parser", about = "Parse an Input file and save its JSON representation")]
|
||||
struct Opt {
|
||||
/// Path to the input file.
|
||||
#[structopt(parse(from_os_str))]
|
||||
@ -47,10 +44,7 @@ struct Opt {
|
||||
fn main() -> Result<(), String> {
|
||||
let opt = Opt::parse();
|
||||
let input_tree = create_session_if_not_set_then(|s| {
|
||||
let input_string = s
|
||||
.source_map
|
||||
.load_file(&opt.input_path)
|
||||
.expect("failed to open an input file");
|
||||
let input_string = s.source_map.load_file(&opt.input_path).expect("failed to open an input file");
|
||||
|
||||
Handler::with(|handler| {
|
||||
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 {
|
||||
format!(
|
||||
"{}/{}.json",
|
||||
out_dir.as_path().display(),
|
||||
opt.input_path.file_stem().unwrap().to_str().unwrap()
|
||||
)
|
||||
format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
} else {
|
||||
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
};
|
||||
|
@ -62,11 +62,7 @@ fn main() -> Result<(), String> {
|
||||
}
|
||||
|
||||
let out_path = if let Some(out_dir) = opt.out_dir_path {
|
||||
format!(
|
||||
"{}/{}.json",
|
||||
out_dir.as_path().display(),
|
||||
opt.input_path.file_stem().unwrap().to_str().unwrap()
|
||||
)
|
||||
format!("{}/{}.json", out_dir.as_path().display(), opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
} else {
|
||||
format!("./{}.json", opt.input_path.file_stem().unwrap().to_str().unwrap())
|
||||
};
|
||||
|
@ -32,8 +32,7 @@ pub mod parser;
|
||||
pub use parser::*;
|
||||
|
||||
use leo_ast::{input::InputData, Ast, ProgramInput};
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_errors::Result;
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
@ -17,12 +17,10 @@
|
||||
use crate::{tokenizer::*, Token};
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_errors::{ParserError, ParserWarning, Result};
|
||||
use leo_errors::{emitter::Handler, ParserError, ParserWarning, Result};
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use std::fmt::Display;
|
||||
use std::mem;
|
||||
use std::{fmt::Display, mem};
|
||||
|
||||
/// Stores a program in tokenized format plus additional context.
|
||||
/// 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.
|
||||
const DUMMY_EOF: SpannedToken = SpannedToken {
|
||||
token: Token::Eof,
|
||||
span: Span::dummy(),
|
||||
};
|
||||
const DUMMY_EOF: SpannedToken = SpannedToken { token: Token::Eof, span: Span::dummy() };
|
||||
|
||||
impl<'a> ParserContext<'a> {
|
||||
/// 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.
|
||||
let next_token = self.tokens.pop().unwrap_or(SpannedToken {
|
||||
token: Token::Eof,
|
||||
span: self.token.span,
|
||||
});
|
||||
let next_token = self.tokens.pop().unwrap_or(SpannedToken { token: Token::Eof, span: self.token.span });
|
||||
|
||||
// Set the new 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.
|
||||
pub(super) fn expect(&mut self, token: &Token) -> Result<Span> {
|
||||
if self.eat(token) {
|
||||
Ok(self.prev_token.span)
|
||||
} else {
|
||||
self.unexpected(token)
|
||||
}
|
||||
if self.eat(token) { Ok(self.prev_token.span) } else { self.unexpected(token) }
|
||||
}
|
||||
|
||||
/// Eats one of the expected `tokens`, or errors.
|
||||
|
@ -215,10 +215,7 @@ impl ParserContext<'_> {
|
||||
///
|
||||
/// Otherwise, tries to parse the next token using [`parse_exponential_expression`].
|
||||
fn parse_multiplicative_expression(&mut self) -> Result<Expression> {
|
||||
self.parse_bin_expr(
|
||||
&[Token::Mul, Token::Div, Token::Rem],
|
||||
Self::parse_exponential_expression,
|
||||
)
|
||||
self.parse_bin_expr(&[Token::Mul, Token::Div, Token::Rem], Self::parse_exponential_expression)
|
||||
}
|
||||
|
||||
/// 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))
|
||||
}
|
||||
// Otherwise, produce a unary expression.
|
||||
_ => Expression::Unary(UnaryExpression {
|
||||
span: op_span + inner.span(),
|
||||
op,
|
||||
receiver: Box::new(inner),
|
||||
}),
|
||||
_ => Expression::Unary(UnaryExpression { span: op_span + inner.span(), op, receiver: Box::new(inner) }),
|
||||
};
|
||||
}
|
||||
Ok(inner)
|
||||
@ -285,11 +278,7 @@ impl ParserContext<'_> {
|
||||
|
||||
if let (true, Some(op)) = (args.is_empty(), UnaryOperation::from_symbol(method.name)) {
|
||||
// Found an unary operator and the argument list is empty.
|
||||
Ok(Expression::Unary(UnaryExpression {
|
||||
span,
|
||||
op,
|
||||
receiver: Box::new(receiver),
|
||||
}))
|
||||
Ok(Expression::Unary(UnaryExpression { span, op, receiver: Box::new(receiver) }))
|
||||
} 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.
|
||||
Ok(Expression::Binary(BinaryExpression {
|
||||
@ -359,11 +348,8 @@ impl ParserContext<'_> {
|
||||
if self.check_int() {
|
||||
// Eat a tuple member access.
|
||||
let (index, span) = self.eat_integer()?;
|
||||
expr = Expression::Access(AccessExpression::Tuple(TupleAccess {
|
||||
tuple: Box::new(expr),
|
||||
index,
|
||||
span,
|
||||
}))
|
||||
expr =
|
||||
Expression::Access(AccessExpression::Tuple(TupleAccess { tuple: Box::new(expr), index, span }))
|
||||
} else if self.eat(&Token::Leo) {
|
||||
// Eat an external function call.
|
||||
self.eat(&Token::Div); // todo: Make `/` a more general token.
|
||||
@ -484,11 +470,7 @@ impl ParserContext<'_> {
|
||||
let end_span = check_ahead(dist, &Token::Group)?;
|
||||
dist += 1; // Standing at `)` so advance one for 'group'.
|
||||
|
||||
let gt = GroupTuple {
|
||||
span: start_span + &end_span,
|
||||
x: first_gc,
|
||||
y: second_gc,
|
||||
};
|
||||
let gt = GroupTuple { span: start_span + &end_span, x: first_gc, y: second_gc };
|
||||
|
||||
// Eat everything so that this isn't just peeking.
|
||||
for _ in 0..dist {
|
||||
@ -525,15 +507,10 @@ impl ParserContext<'_> {
|
||||
/// struct initialization expression.
|
||||
/// let foo = Foo { x: 1u8 };
|
||||
pub fn parse_struct_init_expression(&mut self, identifier: Identifier) -> Result<Expression> {
|
||||
let (members, _, end) = self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| {
|
||||
p.parse_struct_member().map(Some)
|
||||
})?;
|
||||
let (members, _, end) =
|
||||
self.parse_list(Delimiter::Brace, Some(Token::Comma), |p| p.parse_struct_member().map(Some))?;
|
||||
|
||||
Ok(Expression::Struct(StructExpression {
|
||||
span: identifier.span + end,
|
||||
name: identifier,
|
||||
members,
|
||||
}))
|
||||
Ok(Expression::Struct(StructExpression { span: identifier.span + end, name: identifier, members }))
|
||||
}
|
||||
|
||||
/// Returns an [`Expression`] AST node if the next token is a primary expression:
|
||||
@ -600,14 +577,10 @@ impl ParserContext<'_> {
|
||||
Expression::Identifier(ident)
|
||||
}
|
||||
}
|
||||
Token::SelfLower => Expression::Identifier(Identifier {
|
||||
name: sym::SelfLower,
|
||||
span,
|
||||
}),
|
||||
t if crate::type_::TYPE_TOKENS.contains(&t) => Expression::Identifier(Identifier {
|
||||
name: t.keyword_to_symbol().unwrap(),
|
||||
span,
|
||||
}),
|
||||
Token::SelfLower => Expression::Identifier(Identifier { name: sym::SelfLower, span }),
|
||||
t if crate::type_::TYPE_TOKENS.contains(&t) => {
|
||||
Expression::Identifier(Identifier { name: t.keyword_to_symbol().unwrap(), span })
|
||||
}
|
||||
token => {
|
||||
return Err(ParserError::unexpected_str(token, "expression", span).into());
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
use super::*;
|
||||
use crate::parse_ast;
|
||||
use leo_errors::{CompilerError, ParserError, Result};
|
||||
use leo_span::source_map::FileName;
|
||||
use leo_span::symbol::with_session_globals;
|
||||
use leo_span::{source_map::FileName, symbol::with_session_globals};
|
||||
|
||||
use std::fs;
|
||||
|
||||
@ -57,10 +56,7 @@ impl ParserContext<'_> {
|
||||
return Err(ParserError::missing_program_scope(self.token.span).into());
|
||||
}
|
||||
|
||||
Ok(Program {
|
||||
imports,
|
||||
program_scopes,
|
||||
})
|
||||
Ok(Program { imports, program_scopes })
|
||||
}
|
||||
|
||||
fn unexpected_item(token: &SpannedToken, expected: &[Token]) -> ParserError {
|
||||
@ -162,19 +158,16 @@ impl ParserContext<'_> {
|
||||
}
|
||||
Token::RightCurly => break,
|
||||
_ => {
|
||||
return Err(Self::unexpected_item(
|
||||
&self.token,
|
||||
&[
|
||||
Token::Struct,
|
||||
Token::Record,
|
||||
Token::Mapping,
|
||||
Token::At,
|
||||
Token::Function,
|
||||
Token::Transition,
|
||||
Token::Inline,
|
||||
],
|
||||
)
|
||||
.into())
|
||||
return Err(Self::unexpected_item(&self.token, &[
|
||||
Token::Struct,
|
||||
Token::Record,
|
||||
Token::Mapping,
|
||||
Token::At,
|
||||
Token::Function,
|
||||
Token::Transition,
|
||||
Token::Inline,
|
||||
])
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -182,13 +175,7 @@ impl ParserContext<'_> {
|
||||
// Parse `}`.
|
||||
let end = self.expect(&Token::RightCurly)?;
|
||||
|
||||
Ok(ProgramScope {
|
||||
program_id,
|
||||
functions,
|
||||
structs,
|
||||
mappings,
|
||||
span: start + end,
|
||||
})
|
||||
Ok(ProgramScope { program_id, functions, structs, mappings, span: start + end })
|
||||
}
|
||||
|
||||
/// 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()?;
|
||||
|
||||
Ok(Member {
|
||||
mode,
|
||||
identifier,
|
||||
type_,
|
||||
span,
|
||||
})
|
||||
Ok(Member { mode, identifier, type_, span })
|
||||
}
|
||||
|
||||
/// Parses a struct or record definition, e.g., `struct Foo { ... }` or `record Foo { ... }`.
|
||||
@ -253,15 +235,7 @@ impl ParserContext<'_> {
|
||||
self.expect(&Token::LeftCurly)?;
|
||||
let (members, end) = self.parse_struct_members()?;
|
||||
|
||||
Ok((
|
||||
struct_name.name,
|
||||
Struct {
|
||||
identifier: struct_name,
|
||||
members,
|
||||
is_record,
|
||||
span: start + end,
|
||||
},
|
||||
))
|
||||
Ok((struct_name.name, Struct { identifier: struct_name, members, is_record, span: start + end }))
|
||||
}
|
||||
|
||||
/// Parses a mapping declaration, e.g. `mapping balances: address => u128`.
|
||||
@ -273,15 +247,7 @@ impl ParserContext<'_> {
|
||||
self.expect(&Token::BigArrow)?;
|
||||
let (value_type, _) = self.parse_type()?;
|
||||
let end = self.expect(&Token::Semicolon)?;
|
||||
Ok((
|
||||
identifier.name,
|
||||
Mapping {
|
||||
identifier,
|
||||
key_type,
|
||||
value_type,
|
||||
span: start + end,
|
||||
},
|
||||
))
|
||||
Ok((identifier.name, Mapping { identifier, key_type, value_type, span: start + end }))
|
||||
}
|
||||
|
||||
// TODO: Return a span associated with the mode.
|
||||
@ -332,21 +298,11 @@ impl ParserContext<'_> {
|
||||
self.eat(&Token::Record);
|
||||
span = span + self.prev_token.span;
|
||||
|
||||
Ok(functions::Input::External(External {
|
||||
identifier: name,
|
||||
program_name: external,
|
||||
record,
|
||||
span,
|
||||
}))
|
||||
Ok(functions::Input::External(External { identifier: name, program_name: external, record, span }))
|
||||
} else {
|
||||
let type_ = self.parse_type()?.0;
|
||||
|
||||
Ok(functions::Input::Internal(FunctionInput {
|
||||
identifier: name,
|
||||
mode,
|
||||
type_,
|
||||
span: name.span,
|
||||
}))
|
||||
Ok(functions::Input::Internal(FunctionInput { identifier: name, mode, type_, span: name.span }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,10 +345,7 @@ impl ParserContext<'_> {
|
||||
}
|
||||
|
||||
fn peek_is_external(&self) -> bool {
|
||||
matches!(
|
||||
(&self.token.token, self.look_ahead(1, |t| &t.token)),
|
||||
(Token::Identifier(_), Token::Dot)
|
||||
)
|
||||
matches!((&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.
|
||||
@ -400,10 +353,7 @@ impl ParserContext<'_> {
|
||||
// Parse the `@` symbol and identifier.
|
||||
let start = self.expect(&Token::At)?;
|
||||
let identifier = match self.token.token {
|
||||
Token::Program => Identifier {
|
||||
name: sym::program,
|
||||
span: self.expect(&Token::Program)?,
|
||||
},
|
||||
Token::Program => Identifier { name: sym::program, span: self.expect(&Token::Program)? },
|
||||
_ => self.expect_identifier()?,
|
||||
};
|
||||
let span = start + identifier.span;
|
||||
@ -490,10 +440,7 @@ impl ParserContext<'_> {
|
||||
};
|
||||
|
||||
let span = start + block.span;
|
||||
Ok((
|
||||
name.name,
|
||||
Function::new(annotations, variant, name, inputs, output, block, finalize, span),
|
||||
))
|
||||
Ok((name.name, Function::new(annotations, variant, name, inputs, output, block, finalize, span)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,11 +55,7 @@ impl ParserContext<'_> {
|
||||
definitions.push(self.parse_input_definition()?);
|
||||
}
|
||||
|
||||
Ok(Section {
|
||||
name: section.name,
|
||||
span: section.span,
|
||||
definitions,
|
||||
})
|
||||
Ok(Section { name: section.name, span: section.span, definitions })
|
||||
}
|
||||
|
||||
/// Parses a single parameter definition:
|
||||
@ -75,12 +71,6 @@ impl ParserContext<'_> {
|
||||
let value = self.parse_unary_expression()?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
|
||||
Ok(Definition {
|
||||
mode,
|
||||
name,
|
||||
type_,
|
||||
value,
|
||||
span,
|
||||
})
|
||||
Ok(Definition { mode, name, type_, value, span })
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,7 @@
|
||||
use crate::{tokenizer::*, Token};
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_errors::Result;
|
||||
use leo_errors::{emitter::Handler, Result};
|
||||
use leo_span::Span;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
|
@ -133,10 +133,7 @@ impl ParserContext<'_> {
|
||||
} else {
|
||||
// Parse the expression as a statement.
|
||||
let end = self.expect(&Token::Semicolon)?;
|
||||
Ok(Statement::Expression(ExpressionStatement {
|
||||
span: place.span() + end,
|
||||
expression: place,
|
||||
}))
|
||||
Ok(Statement::Expression(ExpressionStatement { span: place.span() + end, expression: place }))
|
||||
}
|
||||
}
|
||||
|
||||
@ -174,11 +171,7 @@ impl ParserContext<'_> {
|
||||
};
|
||||
let end = self.expect(&Token::Semicolon)?;
|
||||
let span = start + end;
|
||||
Ok(ReturnStatement {
|
||||
span,
|
||||
expression,
|
||||
finalize_arguments: finalize_args,
|
||||
})
|
||||
Ok(ReturnStatement { span, expression, finalize_arguments: finalize_args })
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
let span = start + end;
|
||||
Ok(DecrementStatement {
|
||||
mapping,
|
||||
index,
|
||||
amount,
|
||||
span,
|
||||
})
|
||||
Ok(DecrementStatement { mapping, index, amount, span })
|
||||
}
|
||||
|
||||
/// 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)?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
let span = start + end;
|
||||
Ok(IncrementStatement {
|
||||
mapping,
|
||||
index,
|
||||
amount,
|
||||
span,
|
||||
})
|
||||
Ok(IncrementStatement { mapping, index, amount, span })
|
||||
}
|
||||
|
||||
/// Returns a [`ConditionalStatement`] AST node if the next tokens represent a conditional statement.
|
||||
@ -316,18 +299,13 @@ impl ParserContext<'_> {
|
||||
));
|
||||
(
|
||||
Default::default(),
|
||||
ConsoleFunction::Assert(Expression::Err(ErrExpression {
|
||||
span: Default::default(),
|
||||
})),
|
||||
ConsoleFunction::Assert(Expression::Err(ErrExpression { span: Default::default() })),
|
||||
)
|
||||
}
|
||||
};
|
||||
self.expect(&Token::Semicolon)?;
|
||||
|
||||
Ok(ConsoleStatement {
|
||||
span: keyword + span,
|
||||
function,
|
||||
})
|
||||
Ok(ConsoleStatement { span: keyword + span, function })
|
||||
}
|
||||
|
||||
/// Returns a [`DefinitionStatement`] AST node if the next tokens represent a definition statement.
|
||||
@ -349,12 +327,6 @@ impl ParserContext<'_> {
|
||||
let value = self.parse_expression()?;
|
||||
self.expect(&Token::Semicolon)?;
|
||||
|
||||
Ok(DefinitionStatement {
|
||||
span: decl_span + value.span(),
|
||||
declaration_type: decl_type,
|
||||
place,
|
||||
type_,
|
||||
value,
|
||||
})
|
||||
Ok(DefinitionStatement { span: decl_span + value.span(), declaration_type: decl_type, place, type_, value })
|
||||
}
|
||||
}
|
||||
|
@ -40,13 +40,7 @@ impl Namespace for TokenNamespace {
|
||||
fn run_test(&self, test: Test) -> Result<Value, String> {
|
||||
create_session_if_not_set_then(|s| {
|
||||
tokenize(test, s).map(|tokens| {
|
||||
Value::String(
|
||||
tokens
|
||||
.into_iter()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<String>>()
|
||||
.join(","),
|
||||
)
|
||||
Value::String(tokens.into_iter().map(|x| x.to_string()).collect::<Vec<String>>().join(","))
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -71,9 +65,7 @@ fn with_handler<T>(
|
||||
) -> Result<T, String> {
|
||||
let (handler, buf) = Handler::new_with_buf();
|
||||
let mut tokens = ParserContext::new(&handler, tokens);
|
||||
let parsed = handler
|
||||
.extend_if_error(logic(&mut tokens))
|
||||
.map_err(|_| buf.extract_errs().to_string())?;
|
||||
let parsed = handler.extend_if_error(logic(&mut tokens)).map_err(|_| buf.extract_errs().to_string())?;
|
||||
not_fully_consumed(&mut tokens)?;
|
||||
Ok(parsed)
|
||||
}
|
||||
@ -84,9 +76,7 @@ fn tokenize(test: Test, s: &SessionGlobals) -> Result<Vec<SpannedToken>, String>
|
||||
}
|
||||
|
||||
fn all_are_comments(tokens: &[SpannedToken]) -> bool {
|
||||
tokens
|
||||
.iter()
|
||||
.all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
|
||||
tokens.iter().all(|x| matches!(x.token, Token::CommentLine(_) | Token::CommentBlock(_)))
|
||||
}
|
||||
|
||||
fn yaml_or_fail<T: Serialize>(value: T) -> Value {
|
||||
|
@ -196,11 +196,7 @@ impl Token {
|
||||
// Otherwise, return the `first_token` that matches the one character.
|
||||
let match_two = |input: &mut Peekable<_>, first_token, second_char, second_token| {
|
||||
input.next();
|
||||
Ok(if input.next_if_eq(&second_char).is_some() {
|
||||
(2, second_token)
|
||||
} else {
|
||||
(1, first_token)
|
||||
})
|
||||
Ok(if input.next_if_eq(&second_char).is_some() { (2, second_token) } else { (1, first_token) })
|
||||
};
|
||||
|
||||
// Returns one token matching one or two characters.
|
||||
@ -281,7 +277,7 @@ impl Token {
|
||||
Token::And,
|
||||
'=',
|
||||
Token::AndAssign,
|
||||
)
|
||||
);
|
||||
}
|
||||
'(' => return match_one(&mut input, Token::LeftParen),
|
||||
')' => return match_one(&mut input, Token::RightParen),
|
||||
@ -296,7 +292,7 @@ impl Token {
|
||||
Token::Pow,
|
||||
'=',
|
||||
Token::PowAssign,
|
||||
)
|
||||
);
|
||||
}
|
||||
'+' => return match_two(&mut input, Token::Add, '=', Token::AddAssign),
|
||||
',' => 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::Colon, ':', Token::DoubleColon),
|
||||
';' => return match_one(&mut input, Token::Semicolon),
|
||||
'<' => {
|
||||
return match_four(
|
||||
&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_four(&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_one(&mut input, Token::LeftSquare),
|
||||
']' => return match_one(&mut input, Token::RightSquare),
|
||||
@ -389,7 +363,7 @@ impl Token {
|
||||
Token::Or,
|
||||
'=',
|
||||
Token::OrAssign,
|
||||
)
|
||||
);
|
||||
}
|
||||
'^' => return match_two(&mut input, Token::BitXor, '=', Token::BitXorAssign),
|
||||
'@' => return Ok((1, Token::At)),
|
||||
@ -451,12 +425,8 @@ impl Token {
|
||||
));
|
||||
}
|
||||
|
||||
Err(ParserError::could_not_lex(
|
||||
input
|
||||
.take_while(|c| *c != ';' && !c.is_whitespace())
|
||||
.collect::<String>(),
|
||||
)
|
||||
.into())
|
||||
Err(ParserError::could_not_lex(input.take_while(|c| *c != ';' && !c.is_whitespace()).collect::<String>())
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,10 +439,7 @@ pub struct SpannedToken {
|
||||
impl SpannedToken {
|
||||
/// Returns a dummy token at a dummy span.
|
||||
pub const fn dummy() -> Self {
|
||||
Self {
|
||||
token: Token::Question,
|
||||
span: Span::dummy(),
|
||||
}
|
||||
Self { token: Token::Question, span: Span::dummy() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,8 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::SymbolTable;
|
||||
use crate::{CallGraph, StructGraph};
|
||||
use crate::{CallGraph, StructGraph, SymbolTable};
|
||||
|
||||
use leo_ast::Function;
|
||||
use leo_span::Symbol;
|
||||
|
@ -25,8 +25,7 @@ mod visit_statements;
|
||||
|
||||
mod visit_type;
|
||||
|
||||
use crate::SymbolTable;
|
||||
use crate::{CallGraph, Pass, StructGraph};
|
||||
use crate::{CallGraph, Pass, StructGraph, SymbolTable};
|
||||
|
||||
use leo_ast::Ast;
|
||||
use leo_errors::Result;
|
||||
|
@ -16,9 +16,23 @@
|
||||
|
||||
use crate::CodeGenerator;
|
||||
use leo_ast::{
|
||||
AccessExpression, AssociatedFunction, BinaryExpression, BinaryOperation, CallExpression, ErrExpression, Expression,
|
||||
Identifier, Literal, MemberAccess, StructExpression, TernaryExpression, TupleExpression, Type, UnaryExpression,
|
||||
UnaryOperation, UnitExpression,
|
||||
AccessExpression,
|
||||
AssociatedFunction,
|
||||
BinaryExpression,
|
||||
BinaryOperation,
|
||||
CallExpression,
|
||||
ErrExpression,
|
||||
Expression,
|
||||
Identifier,
|
||||
Literal,
|
||||
MemberAccess,
|
||||
StructExpression,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
Type,
|
||||
UnaryExpression,
|
||||
UnaryOperation,
|
||||
UnitExpression,
|
||||
};
|
||||
use leo_span::sym;
|
||||
use std::borrow::Borrow;
|
||||
@ -287,13 +301,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
Expression::Identifier(identifier) => identifier.name,
|
||||
_ => unreachable!("Parsing guarantees that all `input.function` is always an identifier."),
|
||||
};
|
||||
let return_type = &self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.functions
|
||||
.get(&function_name)
|
||||
.unwrap()
|
||||
.output_type;
|
||||
let return_type = &self.symbol_table.borrow().functions.get(&function_name).unwrap().output_type;
|
||||
match return_type {
|
||||
Type::Unit => {
|
||||
call_instruction.push(';');
|
||||
|
@ -76,13 +76,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
program_string.push('\n');
|
||||
|
||||
// Visit each mapping in the Leo AST and produce an Aleo mapping declaration.
|
||||
program_string.push_str(
|
||||
&program_scope
|
||||
.mappings
|
||||
.values()
|
||||
.map(|mapping| self.visit_mapping(mapping))
|
||||
.join("\n"),
|
||||
);
|
||||
program_string.push_str(&program_scope.mappings.values().map(|mapping| self.visit_mapping(mapping)).join("\n"));
|
||||
|
||||
// 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.
|
||||
@ -118,17 +112,12 @@ impl<'a> CodeGenerator<'a> {
|
||||
}
|
||||
|
||||
fn visit_struct_or_record(&mut self, struct_: &'a Struct) -> String {
|
||||
if struct_.is_record {
|
||||
self.visit_record(struct_)
|
||||
} else {
|
||||
self.visit_struct(struct_)
|
||||
}
|
||||
if struct_.is_record { self.visit_record(struct_) } else { self.visit_struct(struct_) }
|
||||
}
|
||||
|
||||
fn visit_struct(&mut self, struct_: &'a Struct) -> String {
|
||||
// Add private symbol to composite types.
|
||||
self.composite_mapping
|
||||
.insert(&struct_.identifier.name, (false, String::from("private"))); // todo: private by default here.
|
||||
self.composite_mapping.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.
|
||||
|
||||
@ -143,8 +132,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
fn visit_record(&mut self, record: &'a Struct) -> String {
|
||||
// Add record symbol to composite types.
|
||||
let mut output_string = String::from("record");
|
||||
self.composite_mapping
|
||||
.insert(&record.identifier.name, (true, output_string.clone()));
|
||||
self.composite_mapping.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.
|
||||
|
||||
// Construct and append the record variables.
|
||||
@ -190,8 +178,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
|
||||
let type_string = match input {
|
||||
functions::Input::Internal(input) => {
|
||||
self.variable_mapping
|
||||
.insert(&input.identifier.name, register_string.clone());
|
||||
self.variable_mapping.insert(&input.identifier.name, register_string.clone());
|
||||
let visibility = match (self.is_transition_function, input.mode) {
|
||||
(true, Mode::None) => Mode::Private,
|
||||
_ => input.mode,
|
||||
@ -199,8 +186,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
self.visit_type_with_visibility(&input.type_, visibility)
|
||||
}
|
||||
functions::Input::External(input) => {
|
||||
self.variable_mapping
|
||||
.insert(&input.identifier.name, register_string.clone());
|
||||
self.variable_mapping.insert(&input.identifier.name, register_string.clone());
|
||||
format!("{}.aleo/{}.record", input.program_name, input.record)
|
||||
}
|
||||
};
|
||||
@ -234,8 +220,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
// TODO: Dedup code.
|
||||
let type_string = match input {
|
||||
functions::Input::Internal(input) => {
|
||||
self.variable_mapping
|
||||
.insert(&input.identifier.name, register_string.clone());
|
||||
self.variable_mapping.insert(&input.identifier.name, register_string.clone());
|
||||
|
||||
let visibility = match (self.is_transition_function, input.mode) {
|
||||
(true, Mode::None) => Mode::Public,
|
||||
@ -244,8 +229,7 @@ impl<'a> CodeGenerator<'a> {
|
||||
self.visit_type_with_visibility(&input.type_, visibility)
|
||||
}
|
||||
functions::Input::External(input) => {
|
||||
self.variable_mapping
|
||||
.insert(&input.program_name.name, register_string.clone());
|
||||
self.variable_mapping.insert(&input.program_name.name, register_string.clone());
|
||||
format!("{}.aleo/{}.record", input.program_name, input.record)
|
||||
}
|
||||
};
|
||||
|
@ -17,9 +17,22 @@
|
||||
use crate::CodeGenerator;
|
||||
|
||||
use leo_ast::{
|
||||
AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DecrementStatement,
|
||||
DefinitionStatement, Expression, ExpressionStatement, IncrementStatement, IterationStatement, Mode, Output,
|
||||
ReturnStatement, Statement,
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DecrementStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionStatement,
|
||||
IncrementStatement,
|
||||
IterationStatement,
|
||||
Mode,
|
||||
Output,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
};
|
||||
|
||||
use itertools::Itertools;
|
||||
|
@ -48,10 +48,7 @@ impl Assigner {
|
||||
// Create a new variable for the expression.
|
||||
let name = self.unique_symbol("$var", "$");
|
||||
|
||||
let place = Identifier {
|
||||
name,
|
||||
span: Default::default(),
|
||||
};
|
||||
let place = Identifier { name, span: Default::default() };
|
||||
|
||||
(place, self.simple_assign_statement(place, expr))
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
use leo_span::Symbol;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
|
||||
/// A struct dependency graph.
|
||||
pub type StructGraph = DiGraph<Symbol>;
|
||||
@ -54,10 +53,7 @@ pub struct DiGraph<N: Node> {
|
||||
impl<N: Node> DiGraph<N> {
|
||||
/// Initializes a new `DiGraph` from a vector of source nodes.
|
||||
pub fn new(nodes: IndexSet<N>) -> Self {
|
||||
Self {
|
||||
nodes,
|
||||
edges: IndexMap::new(),
|
||||
}
|
||||
Self { nodes, edges: IndexMap::new() }
|
||||
}
|
||||
|
||||
/// Adds an edge to the graph.
|
||||
|
@ -30,10 +30,7 @@ pub struct RenameTable {
|
||||
impl RenameTable {
|
||||
/// Create a new `RenameTable` with the given parent.
|
||||
pub(crate) fn new(parent: Option<Box<RenameTable>>) -> Self {
|
||||
Self {
|
||||
parent,
|
||||
mapping: IndexMap::new(),
|
||||
}
|
||||
Self { parent, mapping: IndexMap::new() }
|
||||
}
|
||||
|
||||
/// Returns the symbols that were renamed in the current scope.
|
||||
|
@ -146,11 +146,7 @@ impl SymbolTable {
|
||||
/// Returns true if the variable exists in any parent scope
|
||||
pub fn variable_in_parent_scope(&self, symbol: Symbol) -> bool {
|
||||
if let Some(parent) = self.parent.as_ref() {
|
||||
if parent.variables.contains_key(&symbol) {
|
||||
true
|
||||
} else {
|
||||
parent.variable_in_parent_scope(symbol)
|
||||
}
|
||||
if parent.variables.contains_key(&symbol) { true } else { parent.variable_in_parent_scope(symbol) }
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
@ -29,9 +29,6 @@ pub struct DeadCodeEliminator {
|
||||
impl DeadCodeEliminator {
|
||||
/// Initializes a new `DeadCodeEliminator`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
used_variables: Default::default(),
|
||||
is_necessary: false,
|
||||
}
|
||||
Self { used_variables: Default::default(), is_necessary: false }
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,22 @@
|
||||
use crate::DeadCodeEliminator;
|
||||
|
||||
use leo_ast::{
|
||||
AssertStatement, AssertVariant, AssignStatement, Block, ConditionalStatement, ConsoleStatement, DecrementStatement,
|
||||
DefinitionStatement, Expression, ExpressionReconstructor, ExpressionStatement, IncrementStatement,
|
||||
IterationStatement, ReturnStatement, Statement, StatementReconstructor,
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DecrementStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
ExpressionStatement,
|
||||
IncrementStatement,
|
||||
IterationStatement,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
};
|
||||
|
||||
impl StatementReconstructor for DeadCodeEliminator {
|
||||
@ -31,14 +44,12 @@ impl StatementReconstructor for DeadCodeEliminator {
|
||||
let statement = Statement::Assert(AssertStatement {
|
||||
variant: match input.variant {
|
||||
AssertVariant::Assert(expr) => AssertVariant::Assert(self.reconstruct_expression(expr).0),
|
||||
AssertVariant::AssertEq(left, right) => AssertVariant::AssertEq(
|
||||
self.reconstruct_expression(left).0,
|
||||
self.reconstruct_expression(right).0,
|
||||
),
|
||||
AssertVariant::AssertNeq(left, right) => AssertVariant::AssertNeq(
|
||||
self.reconstruct_expression(left).0,
|
||||
self.reconstruct_expression(right).0,
|
||||
),
|
||||
AssertVariant::AssertEq(left, right) => {
|
||||
AssertVariant::AssertEq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
|
||||
}
|
||||
AssertVariant::AssertNeq(left, right) => {
|
||||
AssertVariant::AssertNeq(self.reconstruct_expression(left).0, self.reconstruct_expression(right).0)
|
||||
}
|
||||
},
|
||||
span: input.span,
|
||||
});
|
||||
@ -95,23 +106,13 @@ impl StatementReconstructor for DeadCodeEliminator {
|
||||
/// Reconstructs the statements inside a basic block, eliminating any dead code.
|
||||
fn reconstruct_block(&mut self, block: Block) -> (Block, Self::AdditionalOutput) {
|
||||
// Reconstruct each of the statements in reverse.
|
||||
let mut statements: Vec<Statement> = block
|
||||
.statements
|
||||
.into_iter()
|
||||
.rev()
|
||||
.map(|statement| self.reconstruct_statement(statement).0)
|
||||
.collect();
|
||||
let mut statements: Vec<Statement> =
|
||||
block.statements.into_iter().rev().map(|statement| self.reconstruct_statement(statement).0).collect();
|
||||
|
||||
// Reverse the direction of `statements`.
|
||||
statements.reverse();
|
||||
|
||||
(
|
||||
Block {
|
||||
statements,
|
||||
span: block.span,
|
||||
},
|
||||
Default::default(),
|
||||
)
|
||||
(Block { statements, span: block.span }, Default::default())
|
||||
}
|
||||
|
||||
/// Flattening removes conditional statements from the program.
|
||||
@ -200,10 +201,7 @@ impl StatementReconstructor for DeadCodeEliminator {
|
||||
let statement = Statement::Return(ReturnStatement {
|
||||
expression: self.reconstruct_expression(input.expression).0,
|
||||
finalize_arguments: input.finalize_arguments.map(|arguments| {
|
||||
arguments
|
||||
.into_iter()
|
||||
.map(|argument| self.reconstruct_expression(argument).0)
|
||||
.collect()
|
||||
arguments.into_iter().map(|argument| self.reconstruct_expression(argument).0).collect()
|
||||
}),
|
||||
span: input.span,
|
||||
});
|
||||
|
@ -18,8 +18,17 @@ use crate::Flattener;
|
||||
use itertools::Itertools;
|
||||
|
||||
use leo_ast::{
|
||||
AccessExpression, AssociatedFunction, Expression, ExpressionReconstructor, Member, MemberAccess, Statement,
|
||||
StructExpression, StructVariableInitializer, TernaryExpression, TupleExpression,
|
||||
AccessExpression,
|
||||
AssociatedFunction,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Member,
|
||||
MemberAccess,
|
||||
Statement,
|
||||
StructExpression,
|
||||
StructVariableInitializer,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
};
|
||||
|
||||
// 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 {
|
||||
ty: function.ty,
|
||||
name: function.name,
|
||||
args: function
|
||||
.args
|
||||
.into_iter()
|
||||
.map(|arg| self.reconstruct_expression(arg).0)
|
||||
.collect(),
|
||||
args: function.args.into_iter().map(|arg| self.reconstruct_expression(arg).0).collect(),
|
||||
span: function.span,
|
||||
}))
|
||||
}
|
||||
@ -83,20 +88,10 @@ impl ExpressionReconstructor for Flattener<'_> {
|
||||
// Accumulate any statements produced.
|
||||
statements.extend(stmts);
|
||||
// Accumulate the struct members.
|
||||
members.push(StructVariableInitializer {
|
||||
identifier: member.identifier,
|
||||
expression: Some(expr),
|
||||
});
|
||||
members.push(StructVariableInitializer { 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.
|
||||
@ -224,8 +219,7 @@ impl ExpressionReconstructor for Flattener<'_> {
|
||||
let (identifier, statement) = self.unique_simple_assign_statement(expr);
|
||||
|
||||
// Mark the lhs of the assignment as a struct.
|
||||
self.structs
|
||||
.insert(identifier.name, first_member_struct.identifier.name);
|
||||
self.structs.insert(identifier.name, first_member_struct.identifier.name);
|
||||
|
||||
statements.push(statement);
|
||||
|
||||
@ -261,14 +255,8 @@ impl ExpressionReconstructor for Flattener<'_> {
|
||||
(Expression::Identifier(first), Expression::Identifier(second))
|
||||
if self.structs.contains_key(&first.name) && self.structs.contains_key(&second.name) =>
|
||||
{
|
||||
let first_struct = self
|
||||
.symbol_table
|
||||
.lookup_struct(*self.structs.get(&first.name).unwrap())
|
||||
.unwrap();
|
||||
let second_struct = self
|
||||
.symbol_table
|
||||
.lookup_struct(*self.structs.get(&second.name).unwrap())
|
||||
.unwrap();
|
||||
let first_struct = self.symbol_table.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.
|
||||
assert_eq!(first_struct, second_struct);
|
||||
|
||||
|
@ -19,9 +19,27 @@ use itertools::Itertools;
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use leo_ast::{
|
||||
AssertStatement, AssertVariant, AssignStatement, BinaryExpression, BinaryOperation, Block, ConditionalStatement,
|
||||
ConsoleStatement, DefinitionStatement, Expression, ExpressionReconstructor, Identifier, IterationStatement, Node,
|
||||
ReturnStatement, Statement, StatementReconstructor, TupleExpression, Type, UnaryExpression, UnaryOperation,
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
BinaryExpression,
|
||||
BinaryOperation,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
IterationStatement,
|
||||
Node,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
TupleExpression,
|
||||
Type,
|
||||
UnaryExpression,
|
||||
UnaryOperation,
|
||||
};
|
||||
|
||||
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.
|
||||
// Note that the `unwrap` is safe since the match arm checks that the entry exists.
|
||||
self.tuples.insert(
|
||||
lhs_identifier.name,
|
||||
self.tuples.get(&rhs_identifier.name).unwrap().clone(),
|
||||
);
|
||||
self.tuples.insert(lhs_identifier.name, self.tuples.get(&rhs_identifier.name).unwrap().clone());
|
||||
// Note that tuple assignments are removed from the AST.
|
||||
(Statement::dummy(Default::default()), statements)
|
||||
}
|
||||
@ -205,10 +220,7 @@ impl StatementReconstructor for Flattener<'_> {
|
||||
}
|
||||
(Expression::Identifier(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.
|
||||
(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."),
|
||||
};
|
||||
|
||||
tuple
|
||||
.elements
|
||||
.iter()
|
||||
.zip_eq(output_type.0.iter())
|
||||
.for_each(|(identifier, type_)| {
|
||||
let identifier = match identifier {
|
||||
Expression::Identifier(identifier) => identifier,
|
||||
_ => unreachable!(
|
||||
"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);
|
||||
}
|
||||
});
|
||||
tuple.elements.iter().zip_eq(output_type.0.iter()).for_each(|(identifier, type_)| {
|
||||
let identifier = match identifier {
|
||||
Expression::Identifier(identifier) => identifier,
|
||||
_ => unreachable!("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 {
|
||||
@ -318,13 +324,7 @@ impl StatementReconstructor for Flattener<'_> {
|
||||
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.
|
||||
@ -390,14 +390,11 @@ impl StatementReconstructor for Flattener<'_> {
|
||||
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`.
|
||||
let tuple = self.tuples.get(&identifier.name).unwrap().clone();
|
||||
self.returns.push((
|
||||
guard,
|
||||
ReturnStatement {
|
||||
span: input.span,
|
||||
expression: Expression::Tuple(tuple),
|
||||
finalize_arguments: input.finalize_arguments,
|
||||
},
|
||||
));
|
||||
self.returns.push((guard, ReturnStatement {
|
||||
span: input.span,
|
||||
expression: Expression::Tuple(tuple),
|
||||
finalize_arguments: input.finalize_arguments,
|
||||
}));
|
||||
}
|
||||
// Otherwise, add the expression directly.
|
||||
_ => self.returns.push((guard, input)),
|
||||
|
@ -17,8 +17,19 @@
|
||||
use crate::{Assigner, SymbolTable};
|
||||
|
||||
use leo_ast::{
|
||||
AccessExpression, BinaryExpression, BinaryOperation, Block, Expression, ExpressionReconstructor, Identifier,
|
||||
Member, ReturnStatement, Statement, TernaryExpression, TupleExpression, Type,
|
||||
AccessExpression,
|
||||
BinaryExpression,
|
||||
BinaryOperation,
|
||||
Block,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
Member,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
Type,
|
||||
};
|
||||
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`
|
||||
let mut construct_ternary_assignment = |guard: Expression, if_true: Expression, if_false: Expression| {
|
||||
let place = Identifier {
|
||||
name: self.assigner.unique_symbol(prefix, "$"),
|
||||
span: Default::default(),
|
||||
};
|
||||
let place = Identifier { name: self.assigner.unique_symbol(prefix, "$"), span: Default::default() };
|
||||
let (value, stmts) = self.reconstruct_ternary(TernaryExpression {
|
||||
condition: Box::new(guard),
|
||||
if_true: Box::new(if_true),
|
||||
@ -116,14 +124,11 @@ impl<'a> Flattener<'a> {
|
||||
}
|
||||
};
|
||||
|
||||
let expression = guards
|
||||
.into_iter()
|
||||
.rev()
|
||||
.fold(last_expression, |acc, (guard, expr)| match guard {
|
||||
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),
|
||||
});
|
||||
let expression = guards.into_iter().rev().fold(last_expression, |acc, (guard, expr)| match guard {
|
||||
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)
|
||||
}
|
||||
@ -136,11 +141,8 @@ impl<'a> Flattener<'a> {
|
||||
// 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 struct_ = self.symbol_table.lookup_struct(name).unwrap();
|
||||
let Member { type_, .. } = struct_
|
||||
.members
|
||||
.iter()
|
||||
.find(|member| member.name() == access.name.name)
|
||||
.unwrap();
|
||||
let Member { type_, .. } =
|
||||
struct_.members.iter().find(|member| member.name() == access.name.name).unwrap();
|
||||
match type_ {
|
||||
Type::Identifier(identifier) => Some(identifier.name),
|
||||
_ => None,
|
||||
|
@ -16,8 +16,18 @@
|
||||
|
||||
use crate::{Assigner, RenameTable};
|
||||
use leo_ast::{
|
||||
AssignStatement, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression, ExpressionReconstructor,
|
||||
Identifier, IterationStatement, ProgramReconstructor, Statement, StatementReconstructor, StructExpression,
|
||||
AssignStatement,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
IterationStatement,
|
||||
ProgramReconstructor,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
StructExpression,
|
||||
StructVariableInitializer,
|
||||
};
|
||||
use leo_span::Symbol;
|
||||
@ -34,11 +44,7 @@ pub struct AssignmentRenamer {
|
||||
impl AssignmentRenamer {
|
||||
/// Initialize a new `AssignmentRenamer`.
|
||||
pub fn new(assigner: Assigner) -> Self {
|
||||
Self {
|
||||
assigner,
|
||||
rename_table: RenameTable::new(None),
|
||||
is_lhs: false,
|
||||
}
|
||||
Self { assigner, rename_table: RenameTable::new(None), is_lhs: false }
|
||||
}
|
||||
|
||||
/// Load the internal rename table with a set of entries.
|
||||
@ -56,6 +62,7 @@ impl AssignmentRenamer {
|
||||
|
||||
impl ExpressionReconstructor for AssignmentRenamer {
|
||||
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.
|
||||
fn reconstruct_identifier(&mut self, input: Identifier) -> (Expression, Self::AdditionalOutput) {
|
||||
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),
|
||||
};
|
||||
|
||||
(
|
||||
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.
|
||||
@ -115,14 +119,7 @@ impl StatementReconstructor for AssignmentRenamer {
|
||||
let place = self.reconstruct_expression(input.place).0;
|
||||
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.
|
||||
|
@ -17,8 +17,15 @@
|
||||
use crate::{FunctionInliner, Replacer};
|
||||
|
||||
use leo_ast::{
|
||||
CallExpression, Expression, ExpressionReconstructor, Identifier, ReturnStatement, Statement,
|
||||
StatementReconstructor, UnitExpression, Variant,
|
||||
CallExpression,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
Identifier,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
UnitExpression,
|
||||
Variant,
|
||||
};
|
||||
|
||||
use indexmap::IndexMap;
|
||||
@ -56,12 +63,8 @@ impl ExpressionReconstructor for FunctionInliner<'_> {
|
||||
.collect::<IndexMap<_, _>>();
|
||||
|
||||
// Initializer `self.assignment_renamer` with the function parameters.
|
||||
self.assignment_renamer.load(
|
||||
callee
|
||||
.input
|
||||
.iter()
|
||||
.map(|input| (input.identifier().name, input.identifier().name)),
|
||||
);
|
||||
self.assignment_renamer
|
||||
.load(callee.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.
|
||||
// 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."),
|
||||
}
|
||||
}
|
||||
_ => Expression::Unit(UnitExpression {
|
||||
span: Default::default(),
|
||||
}),
|
||||
_ => Expression::Unit(UnitExpression { span: Default::default() }),
|
||||
};
|
||||
|
||||
(result, inlined_statements)
|
||||
|
@ -33,16 +33,12 @@ impl ProgramReconstructor for FunctionInliner<'_> {
|
||||
// Reconstruct the function.
|
||||
let reconstructed_function = self.reconstruct_function(function);
|
||||
// Add the reconstructed function to the mapping.
|
||||
self.reconstructed_functions
|
||||
.insert(function_name, reconstructed_function);
|
||||
self.reconstructed_functions.insert(function_name, reconstructed_function);
|
||||
}
|
||||
}
|
||||
// Check that `input.functions` is empty.
|
||||
// This is a sanity check to ensure that functions in the program scope have been processed.
|
||||
assert!(
|
||||
input.functions.is_empty(),
|
||||
"All functions in the program scope should have been processed."
|
||||
);
|
||||
assert!(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.
|
||||
let functions = core::mem::take(&mut self.reconstructed_functions);
|
||||
|
@ -17,8 +17,17 @@
|
||||
use crate::FunctionInliner;
|
||||
|
||||
use leo_ast::{
|
||||
AssignStatement, Block, ConditionalStatement, ConsoleStatement, DefinitionStatement, Expression,
|
||||
ExpressionReconstructor, ExpressionStatement, IterationStatement, Statement, StatementReconstructor,
|
||||
AssignStatement,
|
||||
Block,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionReconstructor,
|
||||
ExpressionStatement,
|
||||
IterationStatement,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
};
|
||||
|
||||
impl StatementReconstructor for FunctionInliner<'_> {
|
||||
@ -29,29 +38,15 @@ impl StatementReconstructor for FunctionInliner<'_> {
|
||||
match (input.place, value) {
|
||||
// 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() => {
|
||||
statements.extend(
|
||||
left.elements
|
||||
.into_iter()
|
||||
.zip(right.elements.into_iter())
|
||||
.map(|(lhs, rhs)| {
|
||||
Statement::Assign(Box::new(AssignStatement {
|
||||
place: lhs,
|
||||
value: rhs,
|
||||
span: Default::default(),
|
||||
}))
|
||||
}),
|
||||
);
|
||||
statements.extend(left.elements.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)
|
||||
}
|
||||
|
||||
(place, value) => (
|
||||
Statement::Assign(Box::new(AssignStatement {
|
||||
place,
|
||||
value,
|
||||
span: input.span,
|
||||
})),
|
||||
statements,
|
||||
),
|
||||
(place, value) => {
|
||||
(Statement::Assign(Box::new(AssignStatement { place, value, span: input.span })), statements)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,13 +60,7 @@ impl StatementReconstructor for FunctionInliner<'_> {
|
||||
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.
|
||||
@ -98,10 +87,7 @@ impl StatementReconstructor for FunctionInliner<'_> {
|
||||
// If the resulting expression is a unit expression, return a dummy statement.
|
||||
let statement = match expression {
|
||||
Expression::Unit(_) => Statement::dummy(Default::default()),
|
||||
_ => Statement::Expression(ExpressionStatement {
|
||||
expression,
|
||||
span: input.span,
|
||||
}),
|
||||
_ => Statement::Expression(ExpressionStatement { expression, span: input.span }),
|
||||
};
|
||||
|
||||
(statement, additional_statements)
|
||||
|
@ -15,8 +15,7 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use num_traits::One;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Add;
|
||||
use std::{fmt::Display, ops::Add};
|
||||
|
||||
use leo_ast::Value;
|
||||
use leo_errors::LeoError;
|
||||
@ -47,11 +46,7 @@ pub(crate) struct RangeIterator<I: LoopBound> {
|
||||
|
||||
impl<I: LoopBound> RangeIterator<I> {
|
||||
pub(crate) fn new(start: I, end: I, clusivity: Clusivity) -> Self {
|
||||
Self {
|
||||
end,
|
||||
current: Some(start),
|
||||
clusivity,
|
||||
}
|
||||
Self { end, current: Some(start), clusivity }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,12 +22,7 @@ impl ProgramReconstructor for Unroller<'_> {
|
||||
fn reconstruct_function(&mut self, function: Function) -> Function {
|
||||
// Lookup function metadata in the symbol table.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_fn_symbol(function.identifier.name)
|
||||
.unwrap()
|
||||
.id;
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
let previous_function_index = self.enter_scope(function_index);
|
||||
|
@ -18,8 +18,7 @@ use itertools::Itertools;
|
||||
use leo_ast::*;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use crate::unroller::Unroller;
|
||||
use crate::{VariableSymbol, VariableType};
|
||||
use crate::{unroller::Unroller, VariableSymbol, VariableType};
|
||||
|
||||
impl StatementReconstructor for Unroller<'_> {
|
||||
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 block = Block {
|
||||
statements: input
|
||||
.statements
|
||||
.into_iter()
|
||||
.map(|s| self.reconstruct_statement(s).0)
|
||||
.collect(),
|
||||
statements: input.statements.into_iter().map(|s| self.reconstruct_statement(s).0).collect(),
|
||||
span: input.span,
|
||||
};
|
||||
|
||||
@ -46,32 +41,28 @@ impl StatementReconstructor for Unroller<'_> {
|
||||
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 self.is_unrolling {
|
||||
let declaration = if input.declaration_type == DeclarationType::Const {
|
||||
VariableType::Const
|
||||
} else {
|
||||
VariableType::Mut
|
||||
};
|
||||
let declaration =
|
||||
if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut };
|
||||
|
||||
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
symbol,
|
||||
VariableSymbol {
|
||||
type_,
|
||||
span,
|
||||
declaration,
|
||||
},
|
||||
) {
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration })
|
||||
{
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Insert the variables in the into the symbol table.
|
||||
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) => {
|
||||
let tuple_type = match input.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_)| {
|
||||
let identifier = match expression {
|
||||
@ -80,9 +71,10 @@ impl StatementReconstructor for Unroller<'_> {
|
||||
};
|
||||
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())
|
||||
@ -91,27 +83,22 @@ impl StatementReconstructor for Unroller<'_> {
|
||||
fn reconstruct_iteration(&mut self, input: IterationStatement) -> (Statement, Self::AdditionalOutput) {
|
||||
// We match on start and stop cause loops require
|
||||
// bounds to be constants.
|
||||
match (
|
||||
input.start_value.clone().into_inner(),
|
||||
input.stop_value.clone().into_inner(),
|
||||
) {
|
||||
match (input.start_value.clone().into_inner(), input.stop_value.clone().into_inner()) {
|
||||
(Some(start), Some(stop)) => match (Type::from(&start), Type::from(&stop)) {
|
||||
(Type::Integer(IntegerType::I8), Type::Integer(IntegerType::I8))
|
||||
| (Type::Integer(IntegerType::I16), Type::Integer(IntegerType::I16))
|
||||
| (Type::Integer(IntegerType::I32), Type::Integer(IntegerType::I32))
|
||||
| (Type::Integer(IntegerType::I64), Type::Integer(IntegerType::I64))
|
||||
| (Type::Integer(IntegerType::I128), Type::Integer(IntegerType::I128)) => (
|
||||
self.unroll_iteration_statement::<i128>(input, start, stop),
|
||||
Default::default(),
|
||||
),
|
||||
| (Type::Integer(IntegerType::I128), Type::Integer(IntegerType::I128)) => {
|
||||
(self.unroll_iteration_statement::<i128>(input, start, stop), Default::default())
|
||||
}
|
||||
(Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U8))
|
||||
| (Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U16))
|
||||
| (Type::Integer(IntegerType::U32), Type::Integer(IntegerType::U32))
|
||||
| (Type::Integer(IntegerType::U64), Type::Integer(IntegerType::U64))
|
||||
| (Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128)) => (
|
||||
self.unroll_iteration_statement::<u128>(input, start, stop),
|
||||
Default::default(),
|
||||
),
|
||||
| (Type::Integer(IntegerType::U128), Type::Integer(IntegerType::U128)) => {
|
||||
(self.unroll_iteration_statement::<u128>(input, start, stop), Default::default())
|
||||
}
|
||||
_ => 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.
|
||||
|
@ -15,8 +15,17 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use leo_ast::{
|
||||
Block, DeclarationType, DefinitionStatement, Expression, IntegerType, IterationStatement, Literal, Statement,
|
||||
StatementReconstructor, Type, Value,
|
||||
Block,
|
||||
DeclarationType,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
IntegerType,
|
||||
IterationStatement,
|
||||
Literal,
|
||||
Statement,
|
||||
StatementReconstructor,
|
||||
Type,
|
||||
Value,
|
||||
};
|
||||
use std::cell::RefCell;
|
||||
|
||||
@ -37,29 +46,19 @@ pub struct Unroller<'a> {
|
||||
|
||||
impl<'a> Unroller<'a> {
|
||||
pub(crate) fn new(symbol_table: SymbolTable, handler: &'a Handler) -> Self {
|
||||
Self {
|
||||
symbol_table: RefCell::new(symbol_table),
|
||||
scope_index: 0,
|
||||
handler,
|
||||
is_unrolling: false,
|
||||
}
|
||||
Self { symbol_table: RefCell::new(symbol_table), scope_index: 0, handler, is_unrolling: false }
|
||||
}
|
||||
|
||||
/// Returns the index of the current scope.
|
||||
/// 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 {
|
||||
if self.is_unrolling {
|
||||
self.symbol_table.borrow_mut().insert_block()
|
||||
} else {
|
||||
self.scope_index
|
||||
}
|
||||
if self.is_unrolling { self.symbol_table.borrow_mut().insert_block() } else { self.scope_index }
|
||||
}
|
||||
|
||||
/// Enters a child scope.
|
||||
pub(crate) fn enter_scope(&mut self, index: usize) -> usize {
|
||||
let previous_symbol_table = std::mem::take(&mut self.symbol_table);
|
||||
self.symbol_table
|
||||
.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
|
||||
self.symbol_table.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()));
|
||||
core::mem::replace(&mut self.scope_index, 0)
|
||||
}
|
||||
@ -121,13 +120,11 @@ impl<'a> Unroller<'a> {
|
||||
statements: match input.inclusive {
|
||||
true => {
|
||||
let iter = RangeIterator::new(start, stop, Clusivity::Inclusive);
|
||||
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count))
|
||||
.collect()
|
||||
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)).collect()
|
||||
}
|
||||
false => {
|
||||
let iter = RangeIterator::new(start, stop, Clusivity::Exclusive);
|
||||
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count))
|
||||
.collect()
|
||||
iter.map(|iteration_count| self.unroll_single_iteration(&input, iteration_count)).collect()
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -201,10 +198,7 @@ impl<'a> Unroller<'a> {
|
||||
statements.push(self.reconstruct_statement(s).0);
|
||||
});
|
||||
|
||||
let block = Statement::Block(Block {
|
||||
statements,
|
||||
span: input.block.span,
|
||||
});
|
||||
let block = Statement::Block(Block { statements, span: input.block.span });
|
||||
|
||||
self.is_unrolling = prior_is_unrolling;
|
||||
|
||||
|
@ -17,9 +17,24 @@
|
||||
use crate::StaticSingleAssigner;
|
||||
|
||||
use leo_ast::{
|
||||
AccessExpression, AssociatedFunction, BinaryExpression, CallExpression, Expression, ExpressionConsumer, Identifier,
|
||||
Literal, MemberAccess, Statement, Struct, StructExpression, StructVariableInitializer, TernaryExpression,
|
||||
TupleAccess, TupleExpression, UnaryExpression, UnitExpression,
|
||||
AccessExpression,
|
||||
AssociatedFunction,
|
||||
BinaryExpression,
|
||||
CallExpression,
|
||||
Expression,
|
||||
ExpressionConsumer,
|
||||
Identifier,
|
||||
Literal,
|
||||
MemberAccess,
|
||||
Statement,
|
||||
Struct,
|
||||
StructExpression,
|
||||
StructVariableInitializer,
|
||||
TernaryExpression,
|
||||
TupleAccess,
|
||||
TupleExpression,
|
||||
UnaryExpression,
|
||||
UnitExpression,
|
||||
};
|
||||
use leo_span::{sym, Symbol};
|
||||
|
||||
@ -100,14 +115,12 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
statements.append(&mut right_statements);
|
||||
|
||||
// Construct and accumulate a unique assignment statement storing the result of the binary expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Binary(BinaryExpression {
|
||||
left: Box::new(left_expression),
|
||||
right: Box::new(right_expression),
|
||||
op: input.op,
|
||||
span: input.span,
|
||||
}));
|
||||
let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Binary(BinaryExpression {
|
||||
left: Box::new(left_expression),
|
||||
right: Box::new(right_expression),
|
||||
op: input.op,
|
||||
span: input.span,
|
||||
}));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
@ -129,16 +142,14 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
.collect();
|
||||
|
||||
// Construct and accumulate a new assignment statement for the call expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Call(CallExpression {
|
||||
// Note that we do not rename the function name.
|
||||
function: input.function,
|
||||
// Consume the arguments.
|
||||
arguments,
|
||||
external: input.external,
|
||||
span: input.span,
|
||||
}));
|
||||
let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Call(CallExpression {
|
||||
// Note that we do not rename the function name.
|
||||
function: input.function,
|
||||
// Consume the arguments.
|
||||
arguments,
|
||||
external: input.external,
|
||||
span: input.span,
|
||||
}));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
@ -165,10 +176,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
statements.append(&mut stmts);
|
||||
|
||||
// Return the new member.
|
||||
StructVariableInitializer {
|
||||
identifier: arg.identifier,
|
||||
expression: Some(expression),
|
||||
}
|
||||
StructVariableInitializer { identifier: arg.identifier, expression: Some(expression) }
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -182,10 +190,8 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
let mut reordered_members = Vec::with_capacity(members.len());
|
||||
|
||||
// Collect the members of the init expression into a map.
|
||||
let mut member_map: IndexMap<Symbol, StructVariableInitializer> = members
|
||||
.into_iter()
|
||||
.map(|member| (member.identifier.name, member))
|
||||
.collect();
|
||||
let mut member_map: IndexMap<Symbol, StructVariableInitializer> =
|
||||
members.into_iter().map(|member| (member.identifier.name, member)).collect();
|
||||
|
||||
// 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.
|
||||
@ -209,13 +215,11 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
}
|
||||
|
||||
// Construct and accumulate a new assignment statement for the struct expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Struct(StructExpression {
|
||||
name: input.name,
|
||||
span: input.span,
|
||||
members: reordered_members,
|
||||
}));
|
||||
let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Struct(StructExpression {
|
||||
name: input.name,
|
||||
span: input.span,
|
||||
members: reordered_members,
|
||||
}));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
@ -237,13 +241,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
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.
|
||||
@ -265,14 +263,12 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
statements.append(&mut if_false_statements);
|
||||
|
||||
// Construct and accumulate a unique assignment statement storing the result of the ternary expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Ternary(TernaryExpression {
|
||||
condition: Box::new(cond_expr),
|
||||
if_true: Box::new(if_true_expr),
|
||||
if_false: Box::new(if_false_expr),
|
||||
span: input.span,
|
||||
}));
|
||||
let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Ternary(TernaryExpression {
|
||||
condition: Box::new(cond_expr),
|
||||
if_true: Box::new(if_true_expr),
|
||||
if_false: Box::new(if_false_expr),
|
||||
span: input.span,
|
||||
}));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
@ -296,10 +292,7 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
// Construct and accumulate a new assignment statement for the tuple expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Tuple(TupleExpression {
|
||||
elements,
|
||||
span: input.span,
|
||||
}));
|
||||
.unique_simple_assign_statement(Expression::Tuple(TupleExpression { elements, span: input.span }));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
@ -311,13 +304,11 @@ impl ExpressionConsumer for StaticSingleAssigner<'_> {
|
||||
let (receiver, mut statements) = self.consume_expression(*input.receiver);
|
||||
|
||||
// Construct and accumulate a new assignment statement for the unary expression.
|
||||
let (place, statement) = self
|
||||
.assigner
|
||||
.unique_simple_assign_statement(Expression::Unary(UnaryExpression {
|
||||
op: input.op,
|
||||
receiver: Box::new(receiver),
|
||||
span: input.span,
|
||||
}));
|
||||
let (place, statement) = self.assigner.unique_simple_assign_statement(Expression::Unary(UnaryExpression {
|
||||
op: input.op,
|
||||
receiver: Box::new(receiver),
|
||||
span: input.span,
|
||||
}));
|
||||
statements.push(statement);
|
||||
|
||||
(Expression::Identifier(place), statements)
|
||||
|
@ -17,8 +17,18 @@
|
||||
use crate::StaticSingleAssigner;
|
||||
|
||||
use leo_ast::{
|
||||
Block, Finalize, Function, FunctionConsumer, Member, Program, ProgramConsumer, ProgramScope, ProgramScopeConsumer,
|
||||
StatementConsumer, Struct, StructConsumer,
|
||||
Block,
|
||||
Finalize,
|
||||
Function,
|
||||
FunctionConsumer,
|
||||
Member,
|
||||
Program,
|
||||
ProgramConsumer,
|
||||
ProgramScope,
|
||||
ProgramScopeConsumer,
|
||||
StatementConsumer,
|
||||
Struct,
|
||||
StructConsumer,
|
||||
};
|
||||
use leo_span::{sym, Symbol};
|
||||
|
||||
@ -33,11 +43,8 @@ impl StructConsumer for StaticSingleAssigner<'_> {
|
||||
false => struct_,
|
||||
true => {
|
||||
let mut members = Vec::with_capacity(struct_.members.len());
|
||||
let mut member_map: IndexMap<Symbol, Member> = struct_
|
||||
.members
|
||||
.into_iter()
|
||||
.map(|member| (member.identifier.name, member))
|
||||
.collect();
|
||||
let mut member_map: IndexMap<Symbol, Member> =
|
||||
struct_.members.into_iter().map(|member| (member.identifier.name, member)).collect();
|
||||
|
||||
// Add the owner field to the beginning of the members list.
|
||||
// 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`.
|
||||
// However, for each input, we must add each symbol to the rename table.
|
||||
for input_variable in function.input.iter() {
|
||||
self.rename_table
|
||||
.update(input_variable.identifier().name, input_variable.identifier().name);
|
||||
self.rename_table.update(input_variable.identifier().name, input_variable.identifier().name);
|
||||
}
|
||||
|
||||
let block = Block {
|
||||
span: function.block.span,
|
||||
statements: self.consume_block(function.block),
|
||||
};
|
||||
let block = Block { span: function.block.span, statements: self.consume_block(function.block) };
|
||||
|
||||
// Remove the `RenameTable` for the function.
|
||||
self.pop();
|
||||
@ -86,14 +89,10 @@ impl FunctionConsumer for StaticSingleAssigner<'_> {
|
||||
// There is no need to reconstruct `finalize.inputs`.
|
||||
// However, for each input, we must add each symbol to the rename table.
|
||||
for input_variable in finalize.input.iter() {
|
||||
self.rename_table
|
||||
.update(input_variable.identifier().name, input_variable.identifier().name);
|
||||
self.rename_table.update(input_variable.identifier().name, input_variable.identifier().name);
|
||||
}
|
||||
|
||||
let block = Block {
|
||||
span: finalize.block.span,
|
||||
statements: self.consume_block(finalize.block),
|
||||
};
|
||||
let block = Block { span: finalize.block.span, statements: self.consume_block(finalize.block) };
|
||||
|
||||
// Remove the `RenameTable` for the finalize block.
|
||||
self.pop();
|
||||
@ -128,17 +127,9 @@ impl ProgramScopeConsumer for StaticSingleAssigner<'_> {
|
||||
fn consume_program_scope(&mut self, input: ProgramScope) -> Self::Output {
|
||||
ProgramScope {
|
||||
program_id: input.program_id,
|
||||
structs: input
|
||||
.structs
|
||||
.into_iter()
|
||||
.map(|(i, s)| (i, self.consume_struct(s)))
|
||||
.collect(),
|
||||
structs: input.structs.into_iter().map(|(i, s)| (i, self.consume_struct(s))).collect(),
|
||||
mappings: input.mappings,
|
||||
functions: input
|
||||
.functions
|
||||
.into_iter()
|
||||
.map(|(i, f)| (i, self.consume_function(f)))
|
||||
.collect(),
|
||||
functions: input.functions.into_iter().map(|(i, f)| (i, self.consume_function(f))).collect(),
|
||||
span: input.span,
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,25 @@
|
||||
use crate::{RenameTable, StaticSingleAssigner};
|
||||
|
||||
use leo_ast::{
|
||||
AssertStatement, AssertVariant, AssignStatement, Block, CallExpression, ConditionalStatement, ConsoleStatement,
|
||||
DecrementStatement, DefinitionStatement, Expression, ExpressionConsumer, ExpressionStatement, Identifier,
|
||||
IncrementStatement, IterationStatement, ReturnStatement, Statement, StatementConsumer, TernaryExpression,
|
||||
AssertStatement,
|
||||
AssertVariant,
|
||||
AssignStatement,
|
||||
Block,
|
||||
CallExpression,
|
||||
ConditionalStatement,
|
||||
ConsoleStatement,
|
||||
DecrementStatement,
|
||||
DefinitionStatement,
|
||||
Expression,
|
||||
ExpressionConsumer,
|
||||
ExpressionStatement,
|
||||
Identifier,
|
||||
IncrementStatement,
|
||||
IterationStatement,
|
||||
ReturnStatement,
|
||||
Statement,
|
||||
StatementConsumer,
|
||||
TernaryExpression,
|
||||
TupleExpression,
|
||||
};
|
||||
use leo_span::Symbol;
|
||||
@ -59,10 +75,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
};
|
||||
|
||||
// Add the assert statement to the list of produced statements.
|
||||
statements.push(Statement::Assert(AssertStatement {
|
||||
variant,
|
||||
span: input.span,
|
||||
}));
|
||||
statements.push(Statement::Assert(AssertStatement { variant, span: input.span }));
|
||||
|
||||
statements
|
||||
}
|
||||
@ -88,11 +101,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
|
||||
/// Consumes a `Block`, flattening its constituent `ConditionalStatement`s.
|
||||
fn consume_block(&mut self, block: Block) -> Self::Output {
|
||||
block
|
||||
.statements
|
||||
.into_iter()
|
||||
.flat_map(|statement| self.consume_statement(statement))
|
||||
.collect()
|
||||
block.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.
|
||||
@ -110,10 +119,7 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
self.push();
|
||||
|
||||
// Consume the then-block.
|
||||
let then = Block {
|
||||
span: conditional.then.span,
|
||||
statements: self.consume_block(conditional.then),
|
||||
};
|
||||
let then = Block { span: conditional.then.span, statements: self.consume_block(conditional.then) };
|
||||
|
||||
// Remove the `RenameTable` for the then-block.
|
||||
let if_table = self.pop();
|
||||
@ -156,13 +162,9 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
if self.rename_table.lookup(**symbol).is_some() {
|
||||
// Helper to lookup a symbol and create an argument for the phi function.
|
||||
let create_phi_argument = |table: &RenameTable, symbol: Symbol| {
|
||||
let name = *table
|
||||
.lookup(symbol)
|
||||
.unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program."));
|
||||
Box::new(Expression::Identifier(Identifier {
|
||||
name,
|
||||
span: Default::default(),
|
||||
}))
|
||||
let name =
|
||||
*table.lookup(symbol).unwrap_or_else(|| panic!("Symbol {symbol} should exist in the program."));
|
||||
Box::new(Expression::Identifier(Identifier { name, span: Default::default() }))
|
||||
};
|
||||
|
||||
// Create a new name for the variable written to in the `ConditionalStatement`.
|
||||
@ -178,13 +180,9 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
statements.extend(stmts);
|
||||
|
||||
// Create a new `AssignStatement` for the phi function.
|
||||
let assignment = self.assigner.simple_assign_statement(
|
||||
Identifier {
|
||||
name: new_name,
|
||||
span: Default::default(),
|
||||
},
|
||||
value,
|
||||
);
|
||||
let assignment = self
|
||||
.assigner
|
||||
.simple_assign_statement(Identifier { name: new_name, span: Default::default() }, value);
|
||||
|
||||
// Update the `RenameTable` with the new name of the variable.
|
||||
self.rename_table.update(*(*symbol), new_name);
|
||||
@ -251,15 +249,14 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
}
|
||||
}).collect();
|
||||
statements.push(Statement::Assign(Box::new(AssignStatement {
|
||||
place: Expression::Tuple(TupleExpression {
|
||||
elements,
|
||||
span: Default::default()
|
||||
}),
|
||||
place: Expression::Tuple(TupleExpression { elements, span: Default::default() }),
|
||||
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;
|
||||
|
||||
|
@ -30,12 +30,7 @@ pub struct StaticSingleAssigner<'a> {
|
||||
impl<'a> StaticSingleAssigner<'a> {
|
||||
/// Initializes a new `StaticSingleAssigner` with an empty `RenameTable`.
|
||||
pub(crate) fn new(symbol_table: &'a SymbolTable) -> Self {
|
||||
Self {
|
||||
symbol_table,
|
||||
rename_table: RenameTable::new(None),
|
||||
is_lhs: false,
|
||||
assigner: Assigner::default(),
|
||||
}
|
||||
Self { 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.
|
||||
|
@ -31,10 +31,7 @@ pub struct SymbolTableCreator<'a> {
|
||||
|
||||
impl<'a> SymbolTableCreator<'a> {
|
||||
pub fn new(handler: &'a Handler) -> Self {
|
||||
Self {
|
||||
symbol_table: Default::default(),
|
||||
handler,
|
||||
}
|
||||
Self { symbol_table: Default::default(), handler }
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,17 +55,14 @@ impl<'a> ProgramVisitor<'a> for SymbolTableCreator<'a> {
|
||||
|
||||
fn visit_mapping(&mut self, input: &'a Mapping) {
|
||||
// Add the variable associated with the mapping to the symbol table.
|
||||
if let Err(err) = self.symbol_table.insert_variable(
|
||||
input.identifier.name,
|
||||
VariableSymbol {
|
||||
type_: Type::Mapping(MappingType {
|
||||
key: Box::new(input.key_type.clone()),
|
||||
value: Box::new(input.value_type.clone()),
|
||||
}),
|
||||
span: input.span,
|
||||
declaration: VariableType::Mut,
|
||||
},
|
||||
) {
|
||||
if let Err(err) = self.symbol_table.insert_variable(input.identifier.name, VariableSymbol {
|
||||
type_: Type::Mapping(MappingType {
|
||||
key: Box::new(input.key_type.clone()),
|
||||
value: Box::new(input.value_type.clone()),
|
||||
}),
|
||||
span: input.span,
|
||||
declaration: VariableType::Mut,
|
||||
}) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,7 @@
|
||||
use crate::TypeChecker;
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_errors::TypeCheckerError;
|
||||
use leo_errors::{emitter::Handler, TypeCheckerError};
|
||||
use leo_span::{sym, Span};
|
||||
|
||||
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 let Some(expected) = expected {
|
||||
if &t1 != expected {
|
||||
Some(t1)
|
||||
} else {
|
||||
Some(t2)
|
||||
}
|
||||
if &t1 != expected { Some(t1) } else { Some(t2) }
|
||||
} else {
|
||||
Some(t1)
|
||||
}
|
||||
@ -482,12 +477,9 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
|
||||
// Check function argument types.
|
||||
func.input
|
||||
.iter()
|
||||
.zip(input.arguments.iter())
|
||||
.for_each(|(expected, argument)| {
|
||||
self.visit_expression(argument, &Some(expected.type_()));
|
||||
});
|
||||
func.input.iter().zip(input.arguments.iter()).for_each(|(expected, argument)| {
|
||||
self.visit_expression(argument, &Some(expected.type_()));
|
||||
});
|
||||
|
||||
// Add the call to the call graph.
|
||||
let caller_name = match self.function {
|
||||
@ -524,11 +516,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
// Check struct member types.
|
||||
struct_.members.iter().for_each(|Member { identifier, type_, .. }| {
|
||||
// Lookup struct variable name.
|
||||
if let Some(actual) = input
|
||||
.members
|
||||
.iter()
|
||||
.find(|member| member.identifier.name == identifier.name)
|
||||
{
|
||||
if let Some(actual) = input.members.iter().find(|member| member.identifier.name == identifier.name) {
|
||||
match &actual.expression {
|
||||
// If `expression` is None, then the member uses the identifier shorthand, e.g. `Foo { a }`
|
||||
None => self.visit_identifier(&actual.identifier, &Some(type_.clone())),
|
||||
@ -546,11 +534,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
|
||||
Some(ret)
|
||||
} else {
|
||||
self.emit_err(TypeCheckerError::unknown_sym(
|
||||
"struct",
|
||||
input.name.name,
|
||||
input.name.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::unknown_sym("struct", input.name.name, input.name.span()));
|
||||
None
|
||||
}
|
||||
}
|
||||
@ -655,16 +639,13 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> {
|
||||
));
|
||||
}
|
||||
|
||||
expected_types
|
||||
.iter()
|
||||
.zip(input.elements.iter())
|
||||
.for_each(|(expected, expr)| {
|
||||
// Check that the component expression is not a tuple.
|
||||
if matches!(expr, Expression::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()))
|
||||
}
|
||||
self.visit_expression(expr, &Some(expected.clone()));
|
||||
});
|
||||
expected_types.iter().zip(input.elements.iter()).for_each(|(expected, expr)| {
|
||||
// Check that the component expression is not a tuple.
|
||||
if matches!(expr, Expression::Tuple(_)) {
|
||||
self.emit_err(TypeCheckerError::nested_tuple_expression(expr.span()))
|
||||
}
|
||||
self.visit_expression(expr, &Some(expected.clone()));
|
||||
});
|
||||
|
||||
Some(Type::Tuple(expected_types.clone()))
|
||||
} 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 {
|
||||
// Unit expression are only allowed inside a return statement.
|
||||
if !self.is_return {
|
||||
self.emit_err(TypeCheckerError::unit_expression_only_in_return_statements(
|
||||
input.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::unit_expression_only_in_return_statements(input.span()));
|
||||
}
|
||||
Some(Type::Unit)
|
||||
}
|
||||
|
@ -48,10 +48,7 @@ impl<'a> ProgramVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
|
||||
// Typecheck the program scopes.
|
||||
input
|
||||
.program_scopes
|
||||
.values()
|
||||
.for_each(|scope| self.visit_program_scope(scope));
|
||||
input.program_scopes.values().for_each(|scope| self.visit_program_scope(scope));
|
||||
}
|
||||
|
||||
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.
|
||||
let mut used = HashSet::new();
|
||||
// TODO: Better span to target duplicate member.
|
||||
if !input.members.iter().all(
|
||||
|Member {
|
||||
identifier,
|
||||
type_,
|
||||
span,
|
||||
..
|
||||
}| {
|
||||
// Check that the member types are defined.
|
||||
self.assert_type_is_defined(type_, *span);
|
||||
used.insert(identifier.name)
|
||||
},
|
||||
) {
|
||||
if !input.members.iter().all(|Member { identifier, type_, 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 {
|
||||
TypeCheckerError::duplicate_record_variable(input.name(), input.span())
|
||||
} 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((field, _)) => {
|
||||
self.emit_err(TypeCheckerError::record_var_wrong_type(
|
||||
field,
|
||||
expected_ty,
|
||||
input.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::record_var_wrong_type(field, expected_ty, input.span()));
|
||||
}
|
||||
None => {
|
||||
self.emit_err(TypeCheckerError::required_record_variable(
|
||||
need,
|
||||
expected_ty,
|
||||
input.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::required_record_variable(need, expected_ty, input.span()));
|
||||
}
|
||||
};
|
||||
check_has_field(sym::owner, Type::Address);
|
||||
check_has_field(sym::gates, Type::Integer(IntegerType::U64));
|
||||
}
|
||||
|
||||
for Member {
|
||||
mode,
|
||||
identifier,
|
||||
type_,
|
||||
span,
|
||||
} in input.members.iter()
|
||||
{
|
||||
for Member { mode, identifier, type_, span } in input.members.iter() {
|
||||
// Check that the member type is not a tuple.
|
||||
if matches!(type_, Type::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.
|
||||
// Note that this unwrap is safe since function metadata is stored in a prior pass.
|
||||
let function_index = self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_fn_symbol(function.identifier.name)
|
||||
.unwrap()
|
||||
.id;
|
||||
let function_index = self.symbol_table.borrow().lookup_fn_symbol(function.identifier.name).unwrap().id;
|
||||
|
||||
// Enter the function's scope.
|
||||
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.
|
||||
match self.variant.unwrap() {
|
||||
// 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(
|
||||
TypeCheckerError::transition_function_inputs_cannot_be_const(input_var.span()),
|
||||
),
|
||||
Variant::Transition if input_var.mode() == Mode::Constant => {
|
||||
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.
|
||||
Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => self.emit_err(
|
||||
TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()),
|
||||
),
|
||||
Variant::Standard | Variant::Inline if input_var.mode() != Mode::None => {
|
||||
self.emit_err(TypeCheckerError::regular_function_inputs_cannot_have_modes(input_var.span()))
|
||||
}
|
||||
_ => {} // Do nothing.
|
||||
}
|
||||
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input_var.identifier().name,
|
||||
VariableSymbol {
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
})
|
||||
{
|
||||
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 let Type::Identifier(identifier) = function_output.type_ {
|
||||
if !matches!(function.variant, Variant::Transition)
|
||||
&& self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_struct(identifier.name)
|
||||
.unwrap()
|
||||
.is_record
|
||||
&& self.symbol_table.borrow().lookup_struct(identifier.name).unwrap().is_record
|
||||
{
|
||||
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.
|
||||
if !matches!(function.variant, Variant::Transition) {
|
||||
self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize(
|
||||
finalize.span,
|
||||
));
|
||||
self.emit_err(TypeCheckerError::only_transition_functions_can_have_finalize(finalize.span));
|
||||
}
|
||||
|
||||
// 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()));
|
||||
}
|
||||
// Check for conflicting variable names.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input_var.identifier().name,
|
||||
VariableSymbol {
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(input_var.identifier().name, VariableSymbol {
|
||||
type_: input_var.type_(),
|
||||
span: input_var.identifier().span(),
|
||||
declaration: VariableType::Input(input_var.mode()),
|
||||
},
|
||||
) {
|
||||
})
|
||||
{
|
||||
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.
|
||||
// Note that a finalize block can have only public outputs.
|
||||
if matches!(output_type.mode(), Mode::Constant | Mode::Private) {
|
||||
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(
|
||||
output_type.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::finalize_output_mode_must_be_public(output_type.span()));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -162,10 +162,7 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
self.assert_mapping_type(&mapping_type, input.span());
|
||||
|
||||
match mapping_type {
|
||||
None => self.emit_err(TypeCheckerError::could_not_determine_type(
|
||||
input.mapping,
|
||||
input.mapping.span,
|
||||
)),
|
||||
None => self.emit_err(TypeCheckerError::could_not_determine_type(input.mapping, input.mapping.span)),
|
||||
Some(Type::Mapping(mapping_type)) => {
|
||||
// Check that the index matches the key type of the mapping.
|
||||
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.
|
||||
self.assert_field_group_scalar_int_type(&amount_type, input.amount.span());
|
||||
}
|
||||
Some(mapping_type) => self.emit_err(TypeCheckerError::expected_one_type_of(
|
||||
"mapping",
|
||||
mapping_type,
|
||||
input.mapping.span,
|
||||
)),
|
||||
Some(mapping_type) => {
|
||||
self.emit_err(TypeCheckerError::expected_one_type_of("mapping", mapping_type, input.mapping.span))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_definition(&mut self, input: &'a DefinitionStatement) {
|
||||
let declaration = if input.declaration_type == DeclarationType::Const {
|
||||
VariableType::Const
|
||||
} else {
|
||||
VariableType::Mut
|
||||
};
|
||||
let declaration =
|
||||
if input.declaration_type == DeclarationType::Const { VariableType::Const } else { VariableType::Mut };
|
||||
|
||||
// Check that the type of the definition is defined.
|
||||
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.
|
||||
// Helper to insert the variables into the symbol table.
|
||||
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
symbol,
|
||||
VariableSymbol {
|
||||
type_,
|
||||
span,
|
||||
declaration,
|
||||
},
|
||||
) {
|
||||
if let Err(err) =
|
||||
self.symbol_table.borrow_mut().insert_variable(symbol, VariableSymbol { type_, span, declaration })
|
||||
{
|
||||
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."
|
||||
),
|
||||
};
|
||||
tuple_expression
|
||||
.elements
|
||||
.iter()
|
||||
.zip_eq(tuple_type.0.iter())
|
||||
.for_each(|(expression, type_)| {
|
||||
let identifier = match expression {
|
||||
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)
|
||||
});
|
||||
tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| {
|
||||
let identifier = match expression {
|
||||
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)
|
||||
});
|
||||
}
|
||||
_ => 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) {
|
||||
// Expression statements can only be function calls.
|
||||
if !matches!(input.expression, Expression::Call(_)) {
|
||||
self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(
|
||||
input.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::expression_statement_must_be_function_call(input.span()));
|
||||
} else {
|
||||
// Check the expression.
|
||||
// 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());
|
||||
|
||||
match mapping_type {
|
||||
None => self.emit_err(TypeCheckerError::could_not_determine_type(
|
||||
input.mapping,
|
||||
input.mapping.span,
|
||||
)),
|
||||
None => self.emit_err(TypeCheckerError::could_not_determine_type(input.mapping, input.mapping.span)),
|
||||
Some(Type::Mapping(mapping_type)) => {
|
||||
// Check that the index matches the key type of the mapping.
|
||||
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.
|
||||
self.assert_field_group_scalar_int_type(&amount_type, input.amount.span());
|
||||
}
|
||||
Some(mapping_type) => self.emit_err(TypeCheckerError::expected_one_type_of(
|
||||
"mapping",
|
||||
mapping_type,
|
||||
input.mapping.span,
|
||||
)),
|
||||
Some(mapping_type) => {
|
||||
self.emit_err(TypeCheckerError::expected_one_type_of("mapping", mapping_type, input.mapping.span))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -319,14 +295,11 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
let scope_index = self.create_child_scope();
|
||||
|
||||
// Add the loop variable to the scope of the loop body.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input.variable.name,
|
||||
VariableSymbol {
|
||||
type_: input.type_.clone(),
|
||||
span: input.span(),
|
||||
declaration: VariableType::Const,
|
||||
},
|
||||
) {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(input.variable.name, VariableSymbol {
|
||||
type_: input.type_.clone(),
|
||||
span: input.span(),
|
||||
declaration: VariableType::Const,
|
||||
}) {
|
||||
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
|
||||
// statements should always have some parent block
|
||||
let parent = self.function.unwrap();
|
||||
let return_type = &self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_fn_symbol(parent)
|
||||
.map(|f| match self.is_finalize {
|
||||
// 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(),
|
||||
});
|
||||
let return_type = &self.symbol_table.borrow().lookup_fn_symbol(parent).map(|f| match self.is_finalize {
|
||||
// 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.
|
||||
self.has_return = true;
|
||||
@ -413,13 +382,8 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// 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()).unwrap()` is safe since all functions have been checked to exist.
|
||||
let finalize = self
|
||||
.symbol_table
|
||||
.borrow()
|
||||
.lookup_fn_symbol(self.function.unwrap())
|
||||
.unwrap()
|
||||
.finalize
|
||||
.clone();
|
||||
let finalize =
|
||||
self.symbol_table.borrow().lookup_fn_symbol(self.function.unwrap()).unwrap().finalize.clone();
|
||||
match finalize {
|
||||
None => self.emit_err(TypeCheckerError::finalize_without_finalize_block(input.span())),
|
||||
Some(finalize) => {
|
||||
@ -433,13 +397,9 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
}
|
||||
|
||||
// Check function argument types.
|
||||
finalize
|
||||
.input
|
||||
.iter()
|
||||
.zip(arguments.iter())
|
||||
.for_each(|(expected, argument)| {
|
||||
self.visit_expression(argument, &Some(expected.type_()));
|
||||
});
|
||||
finalize.input.iter().zip(arguments.iter()).for_each(|(expected, argument)| {
|
||||
self.visit_expression(argument, &Some(expected.type_()));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -87,11 +87,8 @@ const UNSIGNED_INT_TYPES: [Type; 5] = [
|
||||
Type::Integer(IntegerType::U128),
|
||||
];
|
||||
|
||||
const MAGNITUDE_TYPES: [Type; 3] = [
|
||||
Type::Integer(IntegerType::U8),
|
||||
Type::Integer(IntegerType::U16),
|
||||
Type::Integer(IntegerType::U32),
|
||||
];
|
||||
const MAGNITUDE_TYPES: [Type; 3] =
|
||||
[Type::Integer(IntegerType::U8), Type::Integer(IntegerType::U16), Type::Integer(IntegerType::U32)];
|
||||
|
||||
impl<'a> TypeChecker<'a> {
|
||||
/// Returns a new type checker given a symbol table and error handler.
|
||||
@ -119,8 +116,7 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Enters a child scope.
|
||||
pub(crate) fn enter_scope(&mut self, index: usize) {
|
||||
let previous_symbol_table = std::mem::take(&mut self.symbol_table);
|
||||
self.symbol_table
|
||||
.swap(previous_symbol_table.borrow().lookup_scope_by_index(index).unwrap());
|
||||
self.symbol_table.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()));
|
||||
}
|
||||
|
||||
@ -137,8 +133,7 @@ impl<'a> TypeChecker<'a> {
|
||||
/// Exits the current scope.
|
||||
pub(crate) fn exit_scope(&mut self, index: usize) {
|
||||
let previous_symbol_table = *self.symbol_table.borrow_mut().parent.take().unwrap();
|
||||
self.symbol_table
|
||||
.swap(previous_symbol_table.lookup_scope_by_index(index).unwrap());
|
||||
self.symbol_table.swap(previous_symbol_table.lookup_scope_by_index(index).unwrap());
|
||||
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.
|
||||
pub(crate) fn assert_type(&self, actual: &Option<Type>, expected: &Type, span: Span) {
|
||||
self.check_type(
|
||||
|actual: &Type| actual.eq_flat(expected),
|
||||
expected.to_string(),
|
||||
actual,
|
||||
span,
|
||||
)
|
||||
self.check_type(|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.
|
||||
pub(crate) fn assert_bool_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| BOOLEAN_TYPE.eq(type_),
|
||||
BOOLEAN_TYPE.to_string(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
self.check_type(|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.
|
||||
@ -213,22 +198,12 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
/// 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) {
|
||||
self.check_type(
|
||||
|type_: &Type| SCALAR_TYPE.eq(type_),
|
||||
SCALAR_TYPE.to_string(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
self.check_type(|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.
|
||||
pub(crate) fn assert_int_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| INT_TYPES.contains(type_),
|
||||
types_to_string(&INT_TYPES),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
self.check_type(|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.
|
||||
@ -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).
|
||||
pub(crate) fn assert_magnitude_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_: &Type| MAGNITUDE_TYPES.contains(type_),
|
||||
types_to_string(&MAGNITUDE_TYPES),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
self.check_type(|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.
|
||||
@ -327,13 +297,7 @@ impl<'a> TypeChecker<'a> {
|
||||
|type_: &Type| {
|
||||
FIELD_TYPE.eq(type_) | GROUP_TYPE.eq(type_) | SCALAR_TYPE.eq(type_) | INT_TYPES.contains(type_)
|
||||
},
|
||||
format!(
|
||||
"{}, {}, {}, {}",
|
||||
FIELD_TYPE,
|
||||
GROUP_TYPE,
|
||||
SCALAR_TYPE,
|
||||
types_to_string(&INT_TYPES),
|
||||
),
|
||||
format!("{}, {}, {}, {}", FIELD_TYPE, GROUP_TYPE, SCALAR_TYPE, types_to_string(&INT_TYPES),),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
@ -347,11 +311,7 @@ impl<'a> TypeChecker<'a> {
|
||||
match CoreInstruction::from_symbols(ident.name, function.name) {
|
||||
None => {
|
||||
// Not a core library struct.
|
||||
self.emit_err(TypeCheckerError::invalid_core_function(
|
||||
ident.name,
|
||||
function.name,
|
||||
ident.span(),
|
||||
));
|
||||
self.emit_err(TypeCheckerError::invalid_core_function(ident.name, function.name, ident.span()));
|
||||
}
|
||||
Some(core_instruction) => return Some(core_instruction),
|
||||
}
|
||||
@ -380,11 +340,7 @@ impl<'a> TypeChecker<'a> {
|
||||
.lookup_struct(identifier.name)
|
||||
.map_or(false, |struct_| struct_.is_record) =>
|
||||
{
|
||||
self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(
|
||||
parent,
|
||||
identifier.name,
|
||||
span,
|
||||
))
|
||||
self.emit_err(TypeCheckerError::struct_or_record_cannot_contain_record(parent, identifier.name, span))
|
||||
}
|
||||
Type::Tuple(tuple_type) => {
|
||||
for type_ in tuple_type.iter() {
|
||||
@ -423,12 +379,7 @@ impl<'a> TypeChecker<'a> {
|
||||
|
||||
/// Emits an error if the type is not a mapping.
|
||||
pub(crate) fn assert_mapping_type(&self, type_: &Option<Type>, span: Span) {
|
||||
self.check_type(
|
||||
|type_| matches!(type_, Type::Mapping(_)),
|
||||
"mapping".to_string(),
|
||||
type_,
|
||||
span,
|
||||
)
|
||||
self.check_type(|type_| matches!(type_, Type::Mapping(_)), "mapping".to_string(), type_, span)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,9 @@
|
||||
use crate::span::{BytePos, CharPos, Pos, Span};
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
fmt, fs, io,
|
||||
fmt,
|
||||
fs,
|
||||
io,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
@ -105,10 +107,7 @@ impl SourceMap {
|
||||
if loc.line_start == loc.line_stop {
|
||||
format!("{}:{}-{}", loc.line_start, loc.col_start, loc.col_stop)
|
||||
} else {
|
||||
format!(
|
||||
"{}:{}-{}:{}",
|
||||
loc.line_start, loc.col_start, loc.line_stop, loc.col_stop
|
||||
)
|
||||
format!("{}:{}-{}:{}", 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_hi = begin.lookup_line(span.hi).unwrap_or(0) + 1;
|
||||
let lo_line_pos = begin.lines[idx_lo];
|
||||
let hi_line_pos = if idx_hi < begin.lines.len() {
|
||||
begin.lines[idx_hi]
|
||||
} else {
|
||||
begin.end_pos
|
||||
};
|
||||
let hi_line_pos = if idx_hi < begin.lines.len() { begin.lines[idx_hi] } else { begin.end_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?
|
||||
pub fn is_not_test_framework() -> bool {
|
||||
std::env::var("LEO_TESTFRAMEWORK")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_owned()
|
||||
.is_empty()
|
||||
std::env::var("LEO_TESTFRAMEWORK").unwrap_or_default().trim().to_owned().is_empty()
|
||||
}
|
||||
|
||||
/// A single source in the [`SourceMap`].
|
||||
@ -215,14 +206,7 @@ impl SourceFile {
|
||||
normalize_src(&mut src);
|
||||
let end_pos = start_pos + BytePos::from_usize(src.len());
|
||||
let (lines, multibyte_chars) = analyze_source_file(&src, start_pos);
|
||||
Self {
|
||||
name,
|
||||
src,
|
||||
start_pos,
|
||||
end_pos,
|
||||
lines,
|
||||
multibyte_chars,
|
||||
}
|
||||
Self { name, src, start_pos, end_pos, lines, multibyte_chars }
|
||||
}
|
||||
|
||||
/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
|
||||
|
@ -42,10 +42,7 @@ impl Span {
|
||||
/// Generates a dummy span with all defaults.
|
||||
/// Should only be used in temporary situations.
|
||||
pub const fn dummy() -> Self {
|
||||
Self {
|
||||
lo: BytePos(0),
|
||||
hi: BytePos(0),
|
||||
}
|
||||
Self { lo: BytePos(0), hi: BytePos(0) }
|
||||
}
|
||||
|
||||
/// Is the span a dummy?
|
||||
|
@ -18,9 +18,12 @@
|
||||
|
||||
use crate::Span;
|
||||
|
||||
use serde::de::{MapAccess, Visitor};
|
||||
use serde::ser::SerializeMap;
|
||||
use serde::{Deserializer, Serializer};
|
||||
use serde::{
|
||||
de::{MapAccess, Visitor},
|
||||
ser::SerializeMap,
|
||||
Deserializer,
|
||||
Serializer,
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
/// The AST contains a few tuple-like enum variants that contain spans.
|
||||
|
@ -16,12 +16,15 @@
|
||||
|
||||
use crate::source_map::SourceMap;
|
||||
|
||||
use core::borrow::Borrow;
|
||||
use core::cmp::PartialEq;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::num::NonZeroU32;
|
||||
use core::ops::Deref;
|
||||
use core::{fmt, str};
|
||||
use core::{
|
||||
borrow::Borrow,
|
||||
cmp::PartialEq,
|
||||
fmt,
|
||||
hash::{Hash, Hasher},
|
||||
num::NonZeroU32,
|
||||
ops::Deref,
|
||||
str,
|
||||
};
|
||||
use fxhash::FxBuildHasher;
|
||||
use indexmap::IndexSet;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
@ -289,10 +292,7 @@ pub struct SessionGlobals {
|
||||
|
||||
impl Default for SessionGlobals {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
symbol_interner: Interner::prefilled(),
|
||||
source_map: SourceMap::default(),
|
||||
}
|
||||
Self { symbol_interner: Interner::prefilled(), source_map: SourceMap::default() }
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,9 +381,7 @@ impl Interner {
|
||||
// arena: <_>::default(),
|
||||
set: init.iter().copied().map(InternedStr::Static).collect(),
|
||||
};
|
||||
Self {
|
||||
inner: RefCell::new(inner),
|
||||
}
|
||||
Self { inner: RefCell::new(inner) }
|
||||
}
|
||||
|
||||
/// Interns `string`, returning a `Symbol` corresponding to it.
|
||||
|
@ -68,13 +68,7 @@ impl<'a> Processor<'a> {
|
||||
// we need a hashmap to pull rules easily
|
||||
let rules: HashMap<String, Rule> = abnf.into_iter().map(|rule| (rule.name().to_string(), rule)).collect();
|
||||
|
||||
Processor {
|
||||
grammar,
|
||||
line: 0,
|
||||
out: String::new(),
|
||||
rules,
|
||||
scope: Scope::Free,
|
||||
}
|
||||
Processor { grammar, line: 0, out: String::new(), rules, scope: Scope::Free }
|
||||
}
|
||||
|
||||
/// Main function for this struct.
|
||||
|
@ -64,15 +64,7 @@ impl Backtraced {
|
||||
where
|
||||
S: ToString,
|
||||
{
|
||||
Self {
|
||||
message: message.to_string(),
|
||||
help,
|
||||
code,
|
||||
code_identifier,
|
||||
type_,
|
||||
error,
|
||||
backtrace,
|
||||
}
|
||||
Self { message: message.to_string(), help, code, code_identifier, type_, error, backtrace }
|
||||
}
|
||||
|
||||
/// Gets the backtraced error exit code.
|
||||
@ -113,11 +105,7 @@ impl Backtraced {
|
||||
|
||||
impl fmt::Display for Backtraced {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let (kind, code) = if self.error {
|
||||
("Error", self.error_code())
|
||||
} else {
|
||||
("Warning", self.warning_code())
|
||||
};
|
||||
let (kind, code) = if self.error { ("Error", self.error_code()) } else { ("Warning", self.warning_code()) };
|
||||
let message = format!("{kind} [{code}]: {message}", message = self.message,);
|
||||
|
||||
// To avoid the color enabling characters for comparison with test expectations.
|
||||
@ -144,17 +132,13 @@ impl fmt::Display for Backtraced {
|
||||
"1" => {
|
||||
let mut printer = BacktracePrinter::default();
|
||||
printer = printer.lib_verbosity(Verbosity::Medium);
|
||||
let trace = printer
|
||||
.format_trace_to_string(&self.backtrace)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let trace = printer.format_trace_to_string(&self.backtrace).map_err(|_| fmt::Error)?;
|
||||
write!(f, "{trace}")?;
|
||||
}
|
||||
"full" => {
|
||||
let mut printer = BacktracePrinter::default();
|
||||
printer = printer.lib_verbosity(Verbosity::Full);
|
||||
let trace = printer
|
||||
.format_trace_to_string(&self.backtrace)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let trace = printer.format_trace_to_string(&self.backtrace).map_err(|_| fmt::Error)?;
|
||||
write!(f, "{trace}")?;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -109,32 +109,20 @@ impl fmt::Display for Formatted {
|
||||
|
||||
let (loc, contents) = with_session_globals(|s| {
|
||||
(
|
||||
s.source_map
|
||||
.span_to_location(self.span)
|
||||
.unwrap_or_else(SpanLocation::dummy),
|
||||
s.source_map
|
||||
.line_contents_of_span(self.span)
|
||||
.unwrap_or_else(|| "<contents unavailable>".to_owned()),
|
||||
s.source_map.span_to_location(self.span).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 (kind, code) = if self.backtrace.error {
|
||||
("Error", self.error_code())
|
||||
} else {
|
||||
("Warning", self.warning_code())
|
||||
};
|
||||
let (kind, code) =
|
||||
if self.backtrace.error { ("Error", self.error_code()) } else { ("Warning", self.warning_code()) };
|
||||
|
||||
let message = format!("{kind} [{code}]: {message}", message = self.backtrace.message,);
|
||||
|
||||
// To avoid the color enabling characters for comparison with test expectations.
|
||||
if std::env::var("LEO_TESTFRAMEWORK")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_owned()
|
||||
.is_empty()
|
||||
{
|
||||
if std::env::var("LEO_TESTFRAMEWORK").unwrap_or_default().trim().to_owned().is_empty() {
|
||||
if self.backtrace.error {
|
||||
write!(f, "{}", message.bold().red())?;
|
||||
} else {
|
||||
@ -180,18 +168,14 @@ impl fmt::Display for Formatted {
|
||||
let mut printer = BacktracePrinter::default();
|
||||
printer = printer.verbosity(Verbosity::Medium);
|
||||
printer = printer.lib_verbosity(Verbosity::Medium);
|
||||
let trace = printer
|
||||
.format_trace_to_string(&self.backtrace.backtrace)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let trace = printer.format_trace_to_string(&self.backtrace.backtrace).map_err(|_| fmt::Error)?;
|
||||
write!(f, "\n{trace}")?;
|
||||
}
|
||||
"full" => {
|
||||
let mut printer = BacktracePrinter::default();
|
||||
printer = printer.verbosity(Verbosity::Full);
|
||||
printer = printer.lib_verbosity(Verbosity::Full);
|
||||
let trace = printer
|
||||
.format_trace_to_string(&self.backtrace.backtrace)
|
||||
.map_err(|_| fmt::Error)?;
|
||||
let trace = printer.format_trace_to_string(&self.backtrace.backtrace).map_err(|_| fmt::Error)?;
|
||||
write!(f, "\n{trace}")?;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -17,10 +17,8 @@
|
||||
use crate::LeoWarning;
|
||||
|
||||
use super::LeoError;
|
||||
use core::default::Default;
|
||||
use core::fmt;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use core::{default::Default, fmt};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
/// Types that are sinks for compiler errors.
|
||||
pub trait Emitter {
|
||||
@ -182,11 +180,7 @@ impl Default for Handler {
|
||||
impl Handler {
|
||||
/// Construct a `Handler` using the given `emitter`.
|
||||
pub fn new(emitter: Box<dyn Emitter>) -> Self {
|
||||
let inner = RefCell::new(HandlerInner {
|
||||
err_count: 0,
|
||||
warn_count: 0,
|
||||
emitter,
|
||||
});
|
||||
let inner = RefCell::new(HandlerInner { err_count: 0, warn_count: 0, emitter });
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
|
@ -14,14 +14,15 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::commands::ALEO_CLI_COMMAND;
|
||||
use crate::{commands::Command, context::Context};
|
||||
use crate::{
|
||||
commands::{Command, ALEO_CLI_COMMAND},
|
||||
context::Context,
|
||||
};
|
||||
|
||||
use leo_ast::Struct;
|
||||
use leo_compiler::{Compiler, CompilerOptions, InputAst};
|
||||
use leo_errors::{CliError, CompilerError, PackageError, Result};
|
||||
use leo_package::source::SourceDirectory;
|
||||
use leo_package::{inputs::InputFile, outputs::OutputsDirectory};
|
||||
use leo_package::{inputs::InputFile, outputs::OutputsDirectory, source::SourceDirectory};
|
||||
use leo_span::symbol::with_session_globals;
|
||||
|
||||
use aleo::commands::Build as AleoBuild;
|
||||
@ -29,12 +30,13 @@ use aleo::commands::Build as AleoBuild;
|
||||
use clap::StructOpt;
|
||||
use indexmap::IndexMap;
|
||||
use snarkvm::prelude::{ProgramID, Testnet3};
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use leo_errors::emitter::Handler;
|
||||
use leo_package::build::BuildDirectory;
|
||||
use leo_package::imports::ImportsDirectory;
|
||||
use leo_package::{build::BuildDirectory, imports::ImportsDirectory};
|
||||
use leo_span::Symbol;
|
||||
use tracing::span::Span;
|
||||
|
||||
@ -226,19 +228,14 @@ fn compile_leo_file(
|
||||
is_import: bool,
|
||||
) -> Result<IndexMap<Symbol, Struct>> {
|
||||
// Construct the Leo file name with extension `foo.leo`.
|
||||
let file_name = file_path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(PackageError::failed_to_get_file_name)?;
|
||||
let file_name =
|
||||
file_path.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
|
||||
// Otherwise, use the program_id found in `package.json`.
|
||||
let program_name = match is_import {
|
||||
false => program_id.name().to_string(),
|
||||
true => file_name
|
||||
.strip_suffix(".leo")
|
||||
.ok_or_else(PackageError::failed_to_get_file_name)?
|
||||
.to_string(),
|
||||
true => file_name.strip_suffix(".leo").ok_or_else(PackageError::failed_to_get_file_name)?.to_string(),
|
||||
};
|
||||
|
||||
// Create the path to the Aleo file.
|
||||
|
@ -16,8 +16,7 @@
|
||||
|
||||
use crate::{commands::Command, context::Context};
|
||||
use leo_errors::Result;
|
||||
use leo_package::build::BuildDirectory;
|
||||
use leo_package::outputs::OutputsDirectory;
|
||||
use leo_package::{build::BuildDirectory, outputs::OutputsDirectory};
|
||||
|
||||
use clap::StructOpt;
|
||||
use colored::Colorize;
|
||||
|
@ -14,8 +14,10 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::commands::ALEO_CLI_COMMAND;
|
||||
use crate::{commands::Command, context::Context};
|
||||
use crate::{
|
||||
commands::{Command, ALEO_CLI_COMMAND},
|
||||
context::Context,
|
||||
};
|
||||
|
||||
use leo_errors::{CliError, PackageError, Result};
|
||||
use leo_package::build::BuildDirectory;
|
||||
|
@ -14,14 +14,12 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::commands::Network;
|
||||
use crate::{
|
||||
commands::{Command, ALEO_CLI_COMMAND},
|
||||
commands::{Command, Network, ALEO_CLI_COMMAND},
|
||||
context::Context,
|
||||
};
|
||||
use leo_errors::{CliError, PackageError, Result};
|
||||
use leo_package::build::BUILD_DIRECTORY_NAME;
|
||||
use leo_package::package::Package;
|
||||
use leo_package::{build::BUILD_DIRECTORY_NAME, package::Package};
|
||||
use snarkvm::file::AleoFile;
|
||||
|
||||
use aleo::commands::New as AleoNew;
|
||||
@ -97,9 +95,7 @@ impl Command for New {
|
||||
aleo_file_path.push(AleoFile::<Network>::main_file_name());
|
||||
|
||||
// Remove the Aleo file from the package directory.
|
||||
aleo_file
|
||||
.remove(&aleo_file_path)
|
||||
.map_err(PackageError::failed_to_remove_aleo_file)?;
|
||||
aleo_file.remove(&aleo_file_path).map_err(PackageError::failed_to_remove_aleo_file)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -15,9 +15,8 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use super::build::BuildOptions;
|
||||
use crate::commands::ALEO_CLI_COMMAND;
|
||||
use crate::{
|
||||
commands::{Build, Command},
|
||||
commands::{Build, Command, ALEO_CLI_COMMAND},
|
||||
context::Context,
|
||||
};
|
||||
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")]
|
||||
name: String,
|
||||
|
||||
#[structopt(
|
||||
name = "INPUTS",
|
||||
help = "The inputs to the program. If none are provided, the input file is used."
|
||||
)]
|
||||
#[structopt(name = "INPUTS", help = "The inputs to the program. If none are provided, the input file is used.")]
|
||||
inputs: Vec<String>,
|
||||
|
||||
#[structopt(flatten)]
|
||||
@ -53,10 +49,7 @@ impl Command for Run {
|
||||
}
|
||||
|
||||
fn prelude(&self, context: Context) -> Result<Self::Input> {
|
||||
(Build {
|
||||
options: self.compiler_options.clone(),
|
||||
})
|
||||
.execute(context)
|
||||
(Build { options: self.compiler_options.clone() }).execute(context)
|
||||
}
|
||||
|
||||
fn apply(self, context: Context, input: Self::Input) -> Result<Self::Output> {
|
||||
|
@ -19,10 +19,10 @@ use leo_errors::{CliError, PackageError, Result};
|
||||
use snarkvm::file::Manifest;
|
||||
|
||||
use leo_package::build::{BuildDirectory, BUILD_DIRECTORY_NAME};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::{
|
||||
env::current_dir,
|
||||
fs::File,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
|
@ -125,10 +125,7 @@ impl<F, T> Format<F, T> {
|
||||
///
|
||||
/// [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> {
|
||||
Format {
|
||||
display_thread_id,
|
||||
..self
|
||||
}
|
||||
Format { display_thread_id, ..self }
|
||||
}
|
||||
|
||||
/// 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
|
||||
pub fn with_thread_names(self, display_thread_name: bool) -> Format<F, T> {
|
||||
Format {
|
||||
display_thread_name,
|
||||
..self
|
||||
}
|
||||
Format { display_thread_name, ..self }
|
||||
}
|
||||
}
|
||||
|
||||
|
39
leo/main.rs
39
leo/main.rs
@ -19,14 +19,12 @@ pub mod context;
|
||||
pub mod logger;
|
||||
pub mod updater;
|
||||
|
||||
use crate::commands::*;
|
||||
use crate::context::*;
|
||||
use crate::{commands::*, context::*};
|
||||
use leo_errors::Result;
|
||||
use leo_span::symbol::create_session_if_not_set_then;
|
||||
|
||||
use clap::StructOpt;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use std::{path::PathBuf, process::exit};
|
||||
|
||||
/// CLI Arguments entry point - includes global parameters and subcommands
|
||||
#[derive(StructOpt, Debug)]
|
||||
@ -44,12 +42,7 @@ pub struct CLI {
|
||||
#[structopt(help = "Custom Aleo PM backend URL", env = "APM_URL")]
|
||||
api: Option<String>,
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
global = true,
|
||||
help = "Optional path to Leo program root folder",
|
||||
parse(from_os_str)
|
||||
)]
|
||||
#[structopt(long, global = true, help = "Optional path to Leo program root folder", parse(from_os_str))]
|
||||
path: Option<PathBuf>,
|
||||
}
|
||||
|
||||
@ -95,15 +88,13 @@ fn set_panic_hook() {
|
||||
#[cfg(not(debug_assertions))]
|
||||
std::panic::set_hook({
|
||||
Box::new(move |e| {
|
||||
eprintln!(
|
||||
"thread `{}` {}",
|
||||
std::thread::current().name().unwrap_or("<unnamed>"),
|
||||
e
|
||||
);
|
||||
eprintln!("thread `{}` {}", std::thread::current().name().unwrap_or("<unnamed>"), e);
|
||||
eprintln!("stack backtrace: \n{:?}", backtrace::Backtrace::new());
|
||||
eprintln!("error: internal compiler error: unexpected panic\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!(
|
||||
"note: {} {} running on {} {}\n",
|
||||
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_release().unwrap_or_else(|e| e.to_string()),
|
||||
);
|
||||
eprintln!(
|
||||
"note: compiler args: {}\n",
|
||||
std::env::args().collect::<Vec<_>>().join(" ")
|
||||
);
|
||||
eprintln!("note: compiler args: {}\n", std::env::args().collect::<Vec<_>>().join(" "));
|
||||
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<()> {
|
||||
if !cli.quiet {
|
||||
// Init logger with optional debug flag.
|
||||
logger::init_logger(
|
||||
"leo",
|
||||
match cli.debug {
|
||||
false => 1,
|
||||
true => 2,
|
||||
},
|
||||
)?;
|
||||
logger::init_logger("leo", match cli.debug {
|
||||
false => 1,
|
||||
true => 2,
|
||||
})?;
|
||||
}
|
||||
|
||||
// Get custom root folder and create context for it.
|
||||
|
@ -16,8 +16,11 @@
|
||||
|
||||
use leo_errors::{PackageError, Result};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{borrow::Cow, fs, path::Path};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub static BUILD_DIRECTORY_NAME: &str = "build/";
|
||||
|
||||
|
@ -17,8 +17,11 @@
|
||||
use crate::parse_file_paths;
|
||||
use leo_errors::{PackageError, Result};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{borrow::Cow, fs, path::Path};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub static IMPORTS_DIRECTORY_NAME: &str = "imports/";
|
||||
|
||||
|
@ -24,7 +24,8 @@ use serde::Deserialize;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs::{
|
||||
File, {self},
|
||||
File,
|
||||
{self},
|
||||
},
|
||||
io::Write,
|
||||
path::Path,
|
||||
@ -39,9 +40,7 @@ pub struct InputFile {
|
||||
|
||||
impl InputFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
Self { package_name: package_name.to_string() }
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> String {
|
||||
@ -67,8 +66,7 @@ impl InputFile {
|
||||
let path = self.setup_file_path(path);
|
||||
let mut file = File::create(path).map_err(PackageError::io_error_input_file)?;
|
||||
|
||||
file.write_all(self.template().as_bytes())
|
||||
.map_err(PackageError::io_error_input_file)?;
|
||||
file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_input_file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -89,8 +87,7 @@ b: u32 = 2u32;
|
||||
if !path.ends_with(INPUTS_DIRECTORY_NAME) {
|
||||
path.to_mut().push(INPUTS_DIRECTORY_NAME);
|
||||
}
|
||||
path.to_mut()
|
||||
.push(format!("{}{INPUT_FILE_EXTENSION}", self.package_name));
|
||||
path.to_mut().push(format!("{}{INPUT_FILE_EXTENSION}", self.package_name));
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -27,8 +27,7 @@ pub mod source;
|
||||
|
||||
use leo_errors::{PackageError, Result};
|
||||
|
||||
use std::fs::ReadDir;
|
||||
use std::{fs, path::PathBuf};
|
||||
use std::{fs, fs::ReadDir, path::PathBuf};
|
||||
|
||||
pub static LEO_FILE_EXTENSION: &str = ".leo";
|
||||
|
||||
|
@ -33,16 +33,12 @@ pub enum Snapshot {
|
||||
|
||||
impl fmt::Display for Snapshot {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Initial => "initial_ast",
|
||||
Self::ImportsResolved => "imports_resolved_ast",
|
||||
Self::TypeInference => "type_inferenced_ast",
|
||||
Self::Canonicalization => "canonicalization_ast",
|
||||
}
|
||||
)
|
||||
write!(f, "{}", match self {
|
||||
Self::Initial => "initial_ast",
|
||||
Self::ImportsResolved => "imports_resolved_ast",
|
||||
Self::TypeInference => "type_inferenced_ast",
|
||||
Self::Canonicalization => "canonicalization_ast",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,10 +54,7 @@ pub struct SnapshotFile {
|
||||
|
||||
impl SnapshotFile {
|
||||
pub fn new(package_name: &str, snapshot: Snapshot) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
snapshot,
|
||||
}
|
||||
Self { package_name: package_name.to_string(), snapshot }
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &Path) -> bool {
|
||||
@ -97,8 +90,7 @@ impl SnapshotFile {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
|
||||
}
|
||||
path.to_mut()
|
||||
.push(format!("{}{AST_SNAPSHOT_FILE_EXTENSION}", self.snapshot));
|
||||
path.to_mut().push(format!("{}{AST_SNAPSHOT_FILE_EXTENSION}", self.snapshot));
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ use serde::Deserialize;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs::{
|
||||
File, {self},
|
||||
File,
|
||||
{self},
|
||||
},
|
||||
io::Write,
|
||||
path::Path,
|
||||
@ -38,9 +39,7 @@ pub struct ChecksumFile {
|
||||
|
||||
impl ChecksumFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
Self { package_name: package_name.to_string() }
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &Path) -> bool {
|
||||
@ -62,8 +61,7 @@ impl ChecksumFile {
|
||||
let path = self.setup_file_path(path);
|
||||
let mut file = File::create(path).map_err(PackageError::io_error_checksum_file)?;
|
||||
|
||||
file.write_all(checksum.as_bytes())
|
||||
.map_err(PackageError::io_error_checksum_file)?;
|
||||
file.write_all(checksum.as_bytes()).map_err(PackageError::io_error_checksum_file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -85,8 +83,7 @@ impl ChecksumFile {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
|
||||
}
|
||||
path.to_mut()
|
||||
.push(format!("{}{CHECKSUM_FILE_EXTENSION}", self.package_name));
|
||||
path.to_mut().push(format!("{}{CHECKSUM_FILE_EXTENSION}", self.package_name));
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -23,7 +23,8 @@ use serde::Deserialize;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs::{
|
||||
File, {self},
|
||||
File,
|
||||
{self},
|
||||
},
|
||||
io::Write,
|
||||
path::Path,
|
||||
@ -38,9 +39,7 @@ pub struct CircuitFile {
|
||||
|
||||
impl CircuitFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
Self { package_name: package_name.to_string() }
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &Path) -> bool {
|
||||
@ -62,8 +61,7 @@ impl CircuitFile {
|
||||
let path = self.setup_file_path(path);
|
||||
let mut file = File::create(path).map_err(PackageError::io_error_circuit_file)?;
|
||||
|
||||
file.write_all(circuit.as_bytes())
|
||||
.map_err(PackageError::io_error_circuit_file)?;
|
||||
file.write_all(circuit.as_bytes()).map_err(PackageError::io_error_circuit_file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -85,8 +83,7 @@ impl CircuitFile {
|
||||
if !path.ends_with(OUTPUTS_DIRECTORY_NAME) {
|
||||
path.to_mut().push(OUTPUTS_DIRECTORY_NAME);
|
||||
}
|
||||
path.to_mut()
|
||||
.push(format!("{}{CIRCUIT_FILE_EXTENSION}", self.package_name));
|
||||
path.to_mut().push(format!("{}{CIRCUIT_FILE_EXTENSION}", self.package_name));
|
||||
}
|
||||
path
|
||||
}
|
||||
|
@ -16,8 +16,11 @@
|
||||
|
||||
use leo_errors::{PackageError, Result};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::{borrow::Cow, fs, path::Path};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
pub static OUTPUTS_DIRECTORY_NAME: &str = "outputs/";
|
||||
|
||||
|
@ -41,12 +41,7 @@ impl Package {
|
||||
return Err(PackageError::invalid_package_name(package_name).into());
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
name: package_name.to_owned(),
|
||||
version: "0.1.0".to_owned(),
|
||||
description: None,
|
||||
license: None,
|
||||
})
|
||||
Ok(Self { name: package_name.to_owned(), version: "0.1.0".to_owned(), description: None, license: None })
|
||||
}
|
||||
|
||||
/// Returns `true` if the package name is valid.
|
||||
|
@ -46,8 +46,7 @@ impl Gitignore {
|
||||
}
|
||||
|
||||
let mut file = File::create(&path).map_err(PackageError::io_error_gitignore_file)?;
|
||||
file.write_all(self.template().as_bytes())
|
||||
.map_err(PackageError::io_error_gitignore_file)?;
|
||||
file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_gitignore_file)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -31,9 +31,7 @@ pub struct MainFile {
|
||||
|
||||
impl MainFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
Self { package_name: package_name.to_string() }
|
||||
}
|
||||
|
||||
pub fn filename() -> String {
|
||||
@ -61,9 +59,7 @@ impl MainFile {
|
||||
}
|
||||
|
||||
let mut file = File::create(&path).map_err(PackageError::io_error_main_file)?;
|
||||
Ok(file
|
||||
.write_all(self.template().as_bytes())
|
||||
.map_err(PackageError::io_error_main_file)?)
|
||||
Ok(file.write_all(self.template().as_bytes()).map_err(PackageError::io_error_main_file)?)
|
||||
}
|
||||
|
||||
// TODO: Generalize to other networks.
|
||||
|
@ -104,10 +104,7 @@ impl Sample {
|
||||
/// Leverages the test-framework to grab all tests
|
||||
/// that are passing compiler tests or marked as benchmark tests.
|
||||
fn load_samples() -> Vec<Self> {
|
||||
get_benches()
|
||||
.into_iter()
|
||||
.map(|(name, input)| Self { name, input })
|
||||
.collect()
|
||||
get_benches().into_iter().map(|(name, input)| Self { name, input }).collect()
|
||||
}
|
||||
|
||||
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) {
|
||||
self.bencher(c, mode, |mut compiler| {
|
||||
let (input, name) = self.data();
|
||||
compiler
|
||||
.parse_program_from_string(input, name)
|
||||
.expect("Failed to parse program");
|
||||
compiler.parse_program_from_string(input, name).expect("Failed to parse program");
|
||||
logic(compiler)
|
||||
});
|
||||
}
|
||||
@ -189,9 +184,8 @@ impl Sample {
|
||||
fn bench_loop_unroller(&self, c: &mut Criterion) {
|
||||
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, _struct_graph, _call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let (symbol_table, _struct_graph, _call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.loop_unrolling_pass(symbol_table);
|
||||
let time = start.elapsed();
|
||||
@ -203,12 +197,9 @@ impl Sample {
|
||||
fn bench_ssa(&self, c: &mut Criterion) {
|
||||
self.bencher_after_parse(c, "full", |mut compiler| {
|
||||
let symbol_table = compiler.symbol_table_pass().expect("failed to generate symbol table");
|
||||
let (symbol_table, _struct_graph, _call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.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, _struct_graph, _call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.loop_unrolling_pass(symbol_table).expect("failed to run loop unrolling pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.static_single_assignment_pass(&symbol_table);
|
||||
let time = start.elapsed();
|
||||
@ -220,15 +211,10 @@ impl Sample {
|
||||
fn bench_flattener(&self, c: &mut Criterion) {
|
||||
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, _struct_graph, _call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let symbol_table = compiler
|
||||
.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 (symbol_table, _struct_graph, _call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.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 out = compiler.flattening_pass(&symbol_table, assigner);
|
||||
let time = start.elapsed();
|
||||
@ -240,18 +226,11 @@ impl Sample {
|
||||
fn bench_inline(&self, c: &mut Criterion) {
|
||||
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, _struct_graph, call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let symbol_table = compiler
|
||||
.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 assigner = compiler
|
||||
.flattening_pass(&symbol_table, assigner)
|
||||
.expect("failed to run flattener pass");
|
||||
let (symbol_table, _struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.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 assigner = compiler.flattening_pass(&symbol_table, assigner).expect("failed to run flattener pass");
|
||||
let start = Instant::now();
|
||||
let out = compiler.function_inlining_pass(&call_graph, assigner);
|
||||
let time = start.elapsed();
|
||||
@ -263,21 +242,12 @@ impl Sample {
|
||||
fn bench_dce(&self, c: &mut Criterion) {
|
||||
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, _struct_graph, call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let symbol_table = compiler
|
||||
.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 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 (symbol_table, _struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.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 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 out = compiler.dead_code_elimination_pass();
|
||||
let time = start.elapsed();
|
||||
@ -289,21 +259,12 @@ impl Sample {
|
||||
fn bench_codegen(&self, c: &mut Criterion) {
|
||||
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, struct_graph, call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let symbol_table = compiler
|
||||
.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 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 (symbol_table, struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.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 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");
|
||||
let start = Instant::now();
|
||||
let out = compiler.code_generation_pass(&symbol_table, &struct_graph, &call_graph);
|
||||
@ -317,25 +278,14 @@ impl Sample {
|
||||
self.bencher(c, "full", |mut compiler| {
|
||||
let (input, name) = self.data();
|
||||
let start = Instant::now();
|
||||
compiler
|
||||
.parse_program_from_string(input, name)
|
||||
.expect("Failed to parse program");
|
||||
compiler.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, struct_graph, call_graph) = compiler
|
||||
.type_checker_pass(symbol_table)
|
||||
.expect("failed to run type check pass");
|
||||
let symbol_table = compiler
|
||||
.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 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");
|
||||
let (symbol_table, struct_graph, call_graph) =
|
||||
compiler.type_checker_pass(symbol_table).expect("failed to run type check pass");
|
||||
let symbol_table = compiler.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 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
|
||||
.code_generation_pass(&symbol_table, &struct_graph, &call_graph)
|
||||
|
@ -27,32 +27,11 @@ pub struct TestFailure {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum TestError {
|
||||
Panicked {
|
||||
test: String,
|
||||
index: usize,
|
||||
error: 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,
|
||||
},
|
||||
Panicked { test: String, index: usize, error: 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,
|
||||
MissingTestConfig,
|
||||
}
|
||||
@ -60,28 +39,13 @@ pub enum TestError {
|
||||
impl fmt::Display for TestError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let format_test = |test: &str| -> String {
|
||||
if test.len() > 50 {
|
||||
String::new()
|
||||
} else {
|
||||
format!("\n\n{test}\n\n")
|
||||
}
|
||||
if test.len() > 50 { String::new() } else { format!("\n\n{test}\n\n") }
|
||||
};
|
||||
match self {
|
||||
TestError::Panicked { test, index, error } => {
|
||||
write!(
|
||||
f,
|
||||
"test #{}: {}encountered a rust panic:\n{}",
|
||||
index + 1,
|
||||
format_test(test),
|
||||
error
|
||||
)
|
||||
write!(f, "test #{}: {}encountered a rust panic:\n{}", index + 1, format_test(test), error)
|
||||
}
|
||||
TestError::UnexpectedOutput {
|
||||
test,
|
||||
index,
|
||||
expected,
|
||||
output,
|
||||
} => {
|
||||
TestError::UnexpectedOutput { test, index, expected, output } => {
|
||||
write!(
|
||||
f,
|
||||
"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))
|
||||
}
|
||||
TestError::FailedAndShouldntHave { test, index, error } => {
|
||||
write!(
|
||||
f,
|
||||
"test #{}: {}failed and shouldn't have:\n{}",
|
||||
index + 1,
|
||||
format_test(test),
|
||||
error
|
||||
)
|
||||
write!(f, "test #{}: {}failed and shouldn't have:\n{}", index + 1, format_test(test), error)
|
||||
}
|
||||
TestError::UnexpectedError {
|
||||
test,
|
||||
expected,
|
||||
output,
|
||||
index,
|
||||
} => {
|
||||
write!(
|
||||
f,
|
||||
"test #{}: {}expected error\n{}\ngot\n{}",
|
||||
index + 1,
|
||||
format_test(test),
|
||||
expected,
|
||||
output
|
||||
)
|
||||
TestError::UnexpectedError { test, 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::MissingTestConfig => write!(f, "missing test config"),
|
||||
@ -132,11 +78,7 @@ pub fn emit_errors(
|
||||
test_index: usize,
|
||||
) -> Option<TestError> {
|
||||
match (output, mode) {
|
||||
(Err(e), _) => Some(TestError::Panicked {
|
||||
test: test.to_string(),
|
||||
index: test_index,
|
||||
error: e.to_string(),
|
||||
}),
|
||||
(Err(e), _) => Some(TestError::Panicked { test: test.to_string(), index: test_index, error: e.to_string() }),
|
||||
(Ok(Ok(output)), TestExpectationMode::Pass) => {
|
||||
// passed and should have
|
||||
if let Some(expected_output) = expected_output.as_ref() {
|
||||
@ -152,15 +94,12 @@ pub fn emit_errors(
|
||||
}
|
||||
None
|
||||
}
|
||||
(Ok(Ok(_tokens)), TestExpectationMode::Fail) => Some(TestError::PassedAndShouldntHave {
|
||||
test: test.to_string(),
|
||||
index: test_index,
|
||||
}),
|
||||
(Ok(Err(err)), TestExpectationMode::Pass) => Some(TestError::FailedAndShouldntHave {
|
||||
test: test.to_string(),
|
||||
error: err.to_string(),
|
||||
index: test_index,
|
||||
}),
|
||||
(Ok(Ok(_tokens)), TestExpectationMode::Fail) => {
|
||||
Some(TestError::PassedAndShouldntHave { test: test.to_string(), index: test_index })
|
||||
}
|
||||
(Ok(Err(err)), TestExpectationMode::Pass) => {
|
||||
Some(TestError::FailedAndShouldntHave { test: test.to_string(), error: err.to_string(), index: test_index })
|
||||
}
|
||||
(Ok(Err(err)), TestExpectationMode::Fail) => {
|
||||
let expected_output: Option<String> =
|
||||
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
Loading…
Reference in New Issue
Block a user