mirror of
https://github.com/AleoHQ/leo.git
synced 2024-11-13 08:47:17 +03:00
WIP support tuples on lhs of definitions
This commit is contained in:
parent
40ff47882f
commit
910d373afd
@ -251,7 +251,7 @@ pub trait StatementReconstructor: ExpressionReconstructor {
|
||||
(
|
||||
Statement::Definition(DefinitionStatement {
|
||||
declaration_type: input.declaration_type,
|
||||
variable_name: input.variable_name,
|
||||
place: input.place,
|
||||
type_: input.type_,
|
||||
value: self.reconstruct_expression(input.value).0,
|
||||
span: input.span,
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{Expression, Identifier, Node, Type};
|
||||
use crate::{Expression, Node, Type};
|
||||
use leo_span::Span;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@ -29,7 +29,7 @@ pub struct DefinitionStatement {
|
||||
/// What sort of declaration is this? `let` or `const`?.
|
||||
pub declaration_type: DeclarationType,
|
||||
/// The bindings / variable names to declare.
|
||||
pub variable_name: Identifier,
|
||||
pub place: Expression,
|
||||
/// The types of the bindings, if specified, or inferred otherwise.
|
||||
pub type_: Type,
|
||||
/// An initializer value for the bindings.
|
||||
@ -41,7 +41,7 @@ pub struct DefinitionStatement {
|
||||
impl fmt::Display for DefinitionStatement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{} ", self.declaration_type)?;
|
||||
write!(f, "{}", self.variable_name)?;
|
||||
write!(f, "{}", self.place)?;
|
||||
write!(f, ": {}", self.type_)?;
|
||||
write!(f, " = {};", self.value)
|
||||
}
|
||||
|
@ -297,7 +297,9 @@ impl ParserContext<'_> {
|
||||
};
|
||||
|
||||
// Parse variable name and type.
|
||||
let (variable_name, type_) = self.parse_typed_ident()?;
|
||||
let place = self.parse_expression()?;
|
||||
self.expect(&Token::Colon)?;
|
||||
let type_ = self.parse_type()?.0;
|
||||
|
||||
self.expect(&Token::Assign)?;
|
||||
let value = self.parse_expression()?;
|
||||
@ -306,7 +308,7 @@ impl ParserContext<'_> {
|
||||
Ok(DefinitionStatement {
|
||||
span: decl_span + value.span(),
|
||||
declaration_type: decl_type,
|
||||
variable_name,
|
||||
place,
|
||||
type_,
|
||||
value,
|
||||
})
|
||||
|
@ -14,7 +14,9 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use itertools::Itertools;
|
||||
use leo_ast::*;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
use crate::unroller::Unroller;
|
||||
use crate::{VariableSymbol, VariableType};
|
||||
@ -50,15 +52,37 @@ impl StatementReconstructor for Unroller<'_> {
|
||||
VariableType::Mut
|
||||
};
|
||||
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input.variable_name.name,
|
||||
VariableSymbol {
|
||||
type_: input.type_.clone(),
|
||||
span: input.span(),
|
||||
declaration,
|
||||
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
symbol,
|
||||
VariableSymbol {
|
||||
type_,
|
||||
span,
|
||||
declaration,
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Insert the variables in the into the symbol table.
|
||||
match &input.place {
|
||||
Expression::Identifier(identifier) => insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration),
|
||||
Expression::Tuple(tuple_expression) => {
|
||||
let tuple_type = match input.type_ {
|
||||
Type::Tuple(ref tuple_type) => tuple_type,
|
||||
_ => unreachable!("Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple.")
|
||||
};
|
||||
tuple_expression.elements.iter().zip_eq(tuple_type.0.iter()).for_each(|(expression, type_)| {
|
||||
let identifier = match expression {
|
||||
Expression::Identifier(identifier) => identifier,
|
||||
_ => unreachable!("Type checking guarantees that if the lhs is a tuple, all of its elements are identifiers.")
|
||||
};
|
||||
insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
|
||||
});
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
_ => unreachable!("Type checking guarantees that the lhs of a `DefinitionStatement` is either an identifier or tuple.")
|
||||
|
||||
}
|
||||
}
|
||||
(Statement::Definition(input), Default::default())
|
||||
|
@ -191,7 +191,7 @@ impl<'a> Unroller<'a> {
|
||||
type_: input.type_.clone(),
|
||||
value: Expression::Literal(value),
|
||||
span: Default::default(),
|
||||
variable_name: input.variable,
|
||||
place: Expression::Identifier(input.variable),
|
||||
})
|
||||
.0,
|
||||
];
|
||||
|
@ -222,8 +222,9 @@ impl StatementConsumer for StaticSingleAssigner<'_> {
|
||||
|
||||
// Then assign a new unique name to the left-hand-side of the definition.
|
||||
// Note that this order is necessary to ensure that the right-hand-side uses the correct name when consuming a complex assignment.
|
||||
// TODO: Remove identifier assumption.
|
||||
self.is_lhs = true;
|
||||
let identifier = match self.consume_identifier(definition.variable_name).0 {
|
||||
let identifier = match self.consume_expression(definition.place).0 {
|
||||
Expression::Identifier(identifier) => identifier,
|
||||
_ => unreachable!("`self.consume_identifier` will always return an `Identifier`."),
|
||||
};
|
||||
|
@ -20,7 +20,7 @@ use leo_ast::{Mode, Type};
|
||||
use leo_span::Span;
|
||||
|
||||
/// An enumeration of the different types of variable type.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum VariableType {
|
||||
Const,
|
||||
Input(Mode),
|
||||
|
@ -15,9 +15,11 @@
|
||||
// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{TypeChecker, VariableSymbol, VariableType};
|
||||
use itertools::Itertools;
|
||||
|
||||
use leo_ast::*;
|
||||
use leo_errors::TypeCheckerError;
|
||||
use leo_span::{Span, Symbol};
|
||||
|
||||
impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
fn visit_statement(&mut self, input: &'a Statement) {
|
||||
@ -212,16 +214,50 @@ impl<'a> StatementVisitor<'a> for TypeChecker<'a> {
|
||||
// Check the expression on the left-hand side.
|
||||
self.visit_expression(&input.value, &Some(input.type_.clone()));
|
||||
|
||||
// Insert the variable into the symbol table.
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
input.variable_name.name,
|
||||
VariableSymbol {
|
||||
type_: input.type_.clone(),
|
||||
span: input.span(),
|
||||
declaration,
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
// TODO: Dedup with unrolling pass.
|
||||
// Helper to insert the variables into the symbol table.
|
||||
let insert_variable = |symbol: Symbol, type_: Type, span: Span, declaration: VariableType| {
|
||||
if let Err(err) = self.symbol_table.borrow_mut().insert_variable(
|
||||
symbol,
|
||||
VariableSymbol {
|
||||
type_,
|
||||
span,
|
||||
declaration,
|
||||
},
|
||||
) {
|
||||
self.handler.emit_err(err);
|
||||
}
|
||||
};
|
||||
|
||||
// Insert the variables in the into the symbol table.
|
||||
match &input.place {
|
||||
Expression::Identifier(identifier) => {
|
||||
insert_variable(identifier.name, input.type_.clone(), identifier.span, declaration)
|
||||
}
|
||||
Expression::Tuple(tuple_expression) => {
|
||||
let tuple_type = match &input.type_ {
|
||||
Type::Tuple(tuple_type) => tuple_type,
|
||||
_ => unreachable!(
|
||||
"Type checking guarantees that if the lhs is a tuple, its associated type is also a tuple."
|
||||
),
|
||||
};
|
||||
tuple_expression
|
||||
.elements
|
||||
.iter()
|
||||
.zip_eq(tuple_type.0.iter())
|
||||
.for_each(|(expression, type_)| {
|
||||
let identifier = match expression {
|
||||
Expression::Identifier(identifier) => identifier,
|
||||
_ => {
|
||||
return self.emit_err(TypeCheckerError::lhs_tuple_element_must_be_an_identifier(
|
||||
expression.span(),
|
||||
))
|
||||
}
|
||||
};
|
||||
insert_variable(identifier.name, type_.clone(), identifier.span, declaration)
|
||||
});
|
||||
}
|
||||
_ => self.emit_err(TypeCheckerError::lhs_must_be_identifier_or_tuple(input.place.span())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,4 +519,18 @@ create_messages!(
|
||||
msg: format!("An expression statement must be a function call."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
lhs_tuple_element_must_be_an_identifier {
|
||||
args: (),
|
||||
msg: format!("Tuples on the left-hand side of a `DefinitionStatement` can only contain identifiers."),
|
||||
help: None,
|
||||
}
|
||||
|
||||
@formatted
|
||||
lhs_must_be_identifier_or_tuple {
|
||||
args: (),
|
||||
msg: format!("The left-hand side of a `DefinitionStatement` can only be a tuple or identifier."),
|
||||
help: None,
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user