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