migrate latest ast changes

This commit is contained in:
gluax 2022-01-28 14:54:35 -08:00
parent 7b54423b41
commit f0b312604d
18 changed files with 181 additions and 126 deletions

4
Cargo.lock generated
View File

@ -1365,6 +1365,7 @@ dependencies = [
"pest",
"serde",
"serde_json",
"smallvec",
"tendril",
]
@ -2655,6 +2656,9 @@ name = "smallvec"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83"
dependencies = [
"serde",
]
[[package]]
name = "snarkvm-algorithms"

View File

@ -18,6 +18,9 @@ license = "GPL-3.0"
edition = "2021"
rust-version = "1.56"
[dependencies]
smallvec = { version = "1.8.0", features = ["serde"] }
[dependencies.leo-input]
path = "../input"
version = "1.5.3"

View File

@ -21,10 +21,14 @@ use std::fmt;
use serde::{Deserialize, Serialize};
/// An array element access expression `array[index]`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArrayAccess {
/// The expression, evaluating to an array, that is being indexed.
pub array: Box<Expression>,
/// The index in `array` that is being accessed.
pub index: Box<Expression>,
/// The span of the entire expression `array[index]`.
pub span: Span,
}

View File

@ -21,11 +21,18 @@ use std::fmt;
use serde::{Deserialize, Serialize};
/// An access to a certain range of elements in an `array`.
///
/// Examples include `array[0..3]`, `array[3..]`, `array[..3]`, and `array[..]`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct ArrayRangeAccess {
/// The array to extract a range of elements from.
pub array: Box<Expression>,
/// The lower bound of the index-range, or the start of the array when `None`.
pub left: Option<Box<Expression>>,
/// The higher bound of the index-range, or the end of the array when `None`.
pub right: Option<Box<Expression>>,
/// A span for the entire expression `array[<range>]`.
pub span: Span,
}

View File

@ -21,11 +21,19 @@ use std::fmt;
use serde::{Deserialize, Serialize};
/// A field access expression `inner.name` to some structure with *named fields*.
///
/// For accesses to a positional fields in e.g., a tuple, see `TupleAccess`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MemberAccess {
/// The structure that the field `name` is being extracted from.
pub inner: Box<Expression>,
/// The name of the field to extract in `inner`.
pub name: Identifier,
/// The span covering all of `inner.name`.
pub span: Span,
// FIXME(Centril): Type information shouldn't be injected into an AST,
// so this field should eventually be removed.
pub type_: Option<crate::Type>,
}

View File

@ -21,12 +21,19 @@ use leo_span::Span;
use serde::{Deserialize, Serialize};
use std::fmt;
/// An access expression to a static member, e.g., a constant in a circuit.
/// An example would be `Foo::Const` or `Foo::function` in `Foo::function()`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct StaticAccess {
/// Represents the container for the static member to access.
/// Usually this is a circuit.
pub inner: Box<Expression>,
/// The static member in `inner` that is being accessed.
pub name: Identifier,
/// An optional type initially None, it is later assigned during type inference snapshot if necessary.
// FIXME(Centril): Shouldn't be in an AST. Remove it as part of an architectural revamp.
pub type_: Option<Type>,
/// The span for the entire expression `inner::name`.
pub span: Span,
}

View File

@ -21,10 +21,14 @@ use std::fmt;
use serde::{Deserialize, Serialize};
/// An tuple access expression, e.g., `tuple.index`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct TupleAccess {
/// An expression evaluating to some tuple type, e.g., `(5, 2)`.
pub tuple: Box<Expression>,
/// The index to access in the tuple expression. E.g., `0` for `(5, 2)` would yield `5`.
pub index: PositiveNumber,
/// The span for the entire expression `tuple.index`.
pub span: Span,
}

View File

@ -21,10 +21,17 @@ use std::fmt;
use serde::{Deserialize, Serialize};
/// A type alias `type name = represents;`.
///
/// That is, `name` will become another name for `represents`.
/// This does not create a new type, that is, `name` is the same type as `represents`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Alias {
/// The new name for `represents`.
pub name: Identifier,
/// A span for the entire `type name = represents;`.
pub span: Span,
/// The type that `name` will evaluate and is equal to.
pub represents: Type,
}

View File

@ -19,9 +19,17 @@ use crate::{CircuitMember, Identifier};
use serde::{Deserialize, Serialize};
use std::fmt;
/// A record type definition, e.g., `circuit Foo { my_field: Bar }`.
/// In some languages these are called `struct`s.
///
/// Type identity is decided by the full path including `circuit_name`,
/// as the record is nominal, not structural.
/// The fields are named so `circuit Foo(u8, u16)` is not allowed.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Circuit {
/// The name of the type in the type system in this module.
pub circuit_name: Identifier,
/// The fields, constant variables, and functions of this structure.
pub members: Vec<CircuitMember>,
}

View File

@ -20,6 +20,7 @@ use serde::{Deserialize, Serialize};
use std::fmt;
#[allow(clippy::large_enum_variant)]
/// A member of a circuit definition.
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum CircuitMember {
/// A static constant in a circuit.

View File

@ -17,11 +17,5 @@
pub mod circuit;
pub use circuit::*;
pub mod circuit_variable_definition;
pub use circuit_variable_definition::*;
pub mod circuit_implied_variable_definition;
pub use circuit_implied_variable_definition::*;
pub mod circuit_member;
pub use circuit_member::*;

View File

@ -18,81 +18,81 @@ use crate::PositiveNumber;
use leo_input::types::ArrayDimensions as InputArrayDimensions;
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
use std::fmt;
use smallvec::{smallvec, SmallVec};
use std::{fmt, ops::Deref};
/// Type for handling different definitions of ArrayDimensions.
/// Can be used in an array [`Type`] or an array initializer [`Expression`].
/// A single array dimension.
#[derive(Clone, Deserialize, Debug, PartialEq, Eq, Hash)]
pub enum ArrayDimensions {
pub enum Dimension {
/// The dimension is `_`, that is unspecified and syntactically unknown.
Unspecified,
/// The dimension was specified, e.g., `5` elements.
Number(PositiveNumber),
Multi(Vec<ArrayDimensions>),
}
impl fmt::Display for Dimension {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Unspecified => write!(f, "_"),
Self::Number(num) => write!(f, "{}", num),
}
}
}
impl Dimension {
/// } Returns `Some(n)` unless the dimension is [`Unspecified`].
pub fn as_specified(&self) -> Option<&PositiveNumber> {
match self {
Self::Unspecified => None,
Self::Number(n) => Some(n),
}
}
/// Returns true if the dimension is known to be zero.
fn is_zero(&self) -> bool {
self.as_specified().filter(|n| n.is_zero()).is_some()
}
}
/// Specifies array dimensions for array [`Type`]s or in array initializer [`Expression`]s.
#[derive(Clone, Deserialize, Debug, PartialEq, Eq, Hash)]
pub struct ArrayDimensions(pub SmallVec<[Dimension; 1]>);
impl Deref for ArrayDimensions {
type Target = [Dimension];
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl ArrayDimensions {
/// Returns `true` if the all array dimensions have been removed.
///
/// This method is called after repeated calls to `remove_first`.
pub fn is_empty(&self) -> bool {
match self {
Self::Multi(dimensions) => dimensions.len() != 0,
Self::Number(_) | Self::Unspecified => false,
}
pub fn single(dim: Dimension) -> Self {
Self(smallvec![dim])
}
/// Returns true if the dimensions are not [`Unspecified`].
pub fn is_specified(&self) -> bool {
match self {
Self::Multi(_) | Self::Number(_) => true,
Self::Unspecified => false,
}
}
pub fn flatten(&self) -> Vec<ArrayDimensions> {
match self {
dimension @ (ArrayDimensions::Number(_) | ArrayDimensions::Unspecified) => vec![dimension.clone()],
ArrayDimensions::Multi(dimensions) => dimensions.iter().flat_map(|dim| dim.flatten()).collect(),
}
!self.contains(&Dimension::Unspecified)
}
/// Returns `true` if there is an array dimension equal to zero.
pub fn is_zero(&self) -> bool {
match self {
ArrayDimensions::Multi(dimensions) => dimensions.iter().any(|a| a.is_zero()),
ArrayDimensions::Number(num) => num.is_zero(),
ArrayDimensions::Unspecified => false,
self.iter().any(|d| d.is_zero())
}
/// Attempts to remove the first dimension from the array, or returns `None` if it doesn't.
pub fn remove_first(&mut self) -> Option<Dimension> {
if self.is_empty() {
None
} else {
Some(self.0.remove(0))
}
}
/// Attempts to remove the first dimension from the array.
///
/// If the first dimension exists, then remove and return `Some(PositiveNumber)`.
/// If the first dimension does not exist, then return `None`.
pub fn remove_first(&mut self) -> Option<ArrayDimensions> {
match self {
Self::Multi(dims) => Some(dims.remove(0)),
_ => None,
}
}
/// Attempts to remove the last dimension from the array.
///
/// If the last dimension exists, then remove and return `Some(PositiveNumber)`.
/// If the last dimension does not exist, then return `None`.
pub fn remove_last(&mut self) -> Option<ArrayDimensions> {
match self {
Self::Multi(dims) => dims.pop(),
_ => None,
}
}
}
impl ArrayDimensions {
/// Returns `PositiveNumber` if `Dimension` is specified, returns `None` otherwise.
pub fn number(&self) -> Option<&PositiveNumber> {
match self {
ArrayDimensions::Number(num) => Some(num),
ArrayDimensions::Unspecified | ArrayDimensions::Multi(_) => None,
}
/// Attempts to remove the last dimension from the array, or returns `None` if it doesn't.
pub fn remove_last(&mut self) -> Option<Dimension> {
self.0.pop()
}
}
@ -102,13 +102,11 @@ impl Serialize for ArrayDimensions {
where
S: Serializer,
{
let dimensions = self.flatten();
let mut seq = serializer.serialize_seq(Some(dimensions.len()))?;
for dimension in dimensions.iter() {
match dimension {
ArrayDimensions::Number(num) => seq.serialize_element(&num)?,
ArrayDimensions::Unspecified => seq.serialize_element(&PositiveNumber { value: "0".into() })?,
ArrayDimensions::Multi(_) => unimplemented!("there are no multi dimensions after flattening"),
let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
for dim in self.0.iter() {
match dim {
Dimension::Number(num) => seq.serialize_element(&num)?,
Dimension::Unspecified => seq.serialize_element(&PositiveNumber { value: "0".into() })?,
}
}
seq.end()
@ -119,12 +117,14 @@ impl Serialize for ArrayDimensions {
impl<'ast> From<InputArrayDimensions<'ast>> for ArrayDimensions {
fn from(dimensions: InputArrayDimensions<'ast>) -> Self {
match dimensions {
InputArrayDimensions::Single(single) => ArrayDimensions::Number(PositiveNumber::from(single.number)),
InputArrayDimensions::Multiple(multiple) => ArrayDimensions::Multi(
InputArrayDimensions::Single(single) => {
Self(smallvec![Dimension::Number(PositiveNumber::from(single.number))])
}
InputArrayDimensions::Multiple(multiple) => Self(
multiple
.numbers
.into_iter()
.map(|num| ArrayDimensions::Number(PositiveNumber::from(num)))
.map(|num| Dimension::Number(PositiveNumber::from(num)))
.collect(),
),
}
@ -133,16 +133,13 @@ impl<'ast> From<InputArrayDimensions<'ast>> for ArrayDimensions {
impl fmt::Display for ArrayDimensions {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ArrayDimensions::Unspecified => write!(f, "_"),
ArrayDimensions::Number(num) => write!(f, "{}", num),
ArrayDimensions::Multi(dimensions) => {
write!(
f,
"({})",
dimensions.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ")
)
}
match &*self.0 {
[dim] => write!(f, "{}", dim),
dimensions => write!(
f,
"({})",
dimensions.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", ")
),
}
}
}

View File

@ -16,26 +16,47 @@
use super::*;
/// An initializer for a single field / variable of a circuit initializer expression.
/// That is, in `Foo { bar: 42, baz }`, this is either `bar: 42`, or `baz`.
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitVariableInitializer {
/// The name of the field / variable to be initialized.
pub identifier: Identifier,
/// The expression to initialize the field with.
/// When `None`, a binding, in scope, with the name will be used instead.
pub expression: Option<Expression>,
}
impl fmt::Display for CircuitVariableInitializer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(expr) = &self.expression {
write!(f, "{}: {}", self.identifier, expr)
} else {
write!(f, "{}", self.identifier)
}
}
}
/// A circuit initialization expression, e.g., `Foo { bar: 42, baz }`.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CircuitInitExpression {
/// The name of the structure type to initialize.
pub name: Identifier,
pub members: Vec<CircuitImpliedVariableDefinition>,
/// Initializer expressions for each of the fields in the circuit.
///
/// N.B. Any functions or member constants in the circuit definition
/// are excluded from this list.
pub members: Vec<CircuitVariableInitializer>,
/// A span from `name` to `}`.
pub span: Span,
}
impl fmt::Display for CircuitInitExpression {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {{", self.name)?;
for (i, member) in self.members.iter().enumerate() {
if let Some(expression) = &member.expression {
write!(f, "{}: {}", member.identifier, expression)?;
} else {
write!(f, "{}", member.identifier)?;
}
if i < self.members.len() - 1 {
write!(f, ", ")?;
}
for member in self.members.iter() {
write!(f, "{}", member)?;
write!(f, ", ")?;
}
write!(f, "}}")
}

View File

@ -14,9 +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::{
ArrayDimensions, CircuitImpliedVariableDefinition, GroupValue, Identifier, IntegerType, Node, SpreadOrExpression,
};
use crate::{ArrayDimensions, GroupValue, Identifier, IntegerType, Node, SpreadOrExpression};
use leo_span::Span;

View File

@ -341,20 +341,16 @@ impl InputValue {
}
}
///
/// Returns a new vector of usize values from an [`ArrayDimensions`] type.
///
/// Attempts to parse each dimension in the array from a `String` to a `usize` value. If parsing
/// is successful, the `usize` value is appended to the return vector. If parsing fails, an error
/// is returned.
///
fn parse_array_dimensions(array_dimensions_type: ArrayDimensions, span: &Span) -> Result<Vec<usize>, InputParserError> {
let dimensions = array_dimensions_type.flatten();
fn parse_array_dimensions(dimensions: ArrayDimensions, span: &Span) -> Result<Vec<usize>, InputParserError> {
// Convert the array dimensions to usize.
let mut result_array_dimensions = Vec::with_capacity(dimensions.len());
for dimension in dimensions {
for dimension in dimensions.iter() {
// Convert the dimension to a string.
let dimension_string = dimension.to_string();

View File

@ -238,10 +238,10 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
self.reducer.reduce_tuple_init(tuple_init, elements)
}
pub fn reduce_circuit_implied_variable_definition(
pub fn reduce_circuit_variable_initializer(
&mut self,
variable: &CircuitImpliedVariableDefinition,
) -> Result<CircuitImpliedVariableDefinition> {
variable: &CircuitVariableInitializer,
) -> Result<CircuitVariableInitializer> {
let identifier = self.reduce_identifier(&variable.identifier)?;
let expression = variable
.expression
@ -250,7 +250,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
.transpose()?;
self.reducer
.reduce_circuit_implied_variable_definition(variable, identifier, expression)
.reduce_circuit_variable_initializer(variable, identifier, expression)
}
pub fn reduce_circuit_init(&mut self, circuit_init: &CircuitInitExpression) -> Result<CircuitInitExpression> {
@ -258,7 +258,7 @@ impl<R: ReconstructingReducer> ReconstructingDirector<R> {
let mut members = vec![];
for member in circuit_init.members.iter() {
members.push(self.reduce_circuit_implied_variable_definition(member)?);
members.push(self.reduce_circuit_variable_initializer(member)?);
}
self.reducer.reduce_circuit_init(circuit_init, name, members)

View File

@ -217,20 +217,20 @@ pub trait ReconstructingReducer {
})
}
fn reduce_circuit_implied_variable_definition(
fn reduce_circuit_variable_initializer(
&mut self,
_variable: &CircuitImpliedVariableDefinition,
_variable: &CircuitVariableInitializer,
identifier: Identifier,
expression: Option<Expression>,
) -> Result<CircuitImpliedVariableDefinition> {
Ok(CircuitImpliedVariableDefinition { identifier, expression })
) -> Result<CircuitVariableInitializer> {
Ok(CircuitVariableInitializer { identifier, expression })
}
fn reduce_circuit_init(
&mut self,
circuit_init: &CircuitInitExpression,
name: Identifier,
members: Vec<CircuitImpliedVariableDefinition>,
members: Vec<CircuitVariableInitializer>,
) -> Result<CircuitInitExpression> {
Ok(CircuitInitExpression {
name,

View File

@ -74,23 +74,19 @@ impl Type {
(Type::IntegerType(left), Type::IntegerType(right)) => left.eq(right),
(Type::Identifier(left), Type::Identifier(right)) => left.eq(right),
(Type::SelfType, Type::SelfType) => true,
(Type::Array(left_type, left_dim), Type::Array(right_type, right_dim)) => {
(Type::Array(left_type, left_dims), Type::Array(right_type, right_dims)) => {
// Convert array dimensions to owned.
let left_dim_owned = left_dim.to_owned();
let right_dim_owned = right_dim.to_owned();
let mut left_dims = left_dims.to_owned();
let mut right_dims = right_dims.to_owned();
// Unable to compare arrays with unspecified sizes.
if !left_dim_owned.is_specified() || !right_dim_owned.is_specified() {
if !left_dims.is_specified() || !right_dims.is_specified() {
return false;
}
// We know that values are Some, safe to unwrap.
let mut left_dim_owned = left_dim_owned;
let mut right_dim_owned = right_dim_owned;
// Remove the first element from both dimensions.
let left_first = left_dim_owned.remove_first();
let right_first = right_dim_owned.remove_first();
let left_first = left_dims.remove_first();
let right_first = right_dims.remove_first();
// Compare the first dimensions.
if left_first.ne(&right_first) {
@ -98,8 +94,8 @@ impl Type {
}
// Create a new array type from the remaining array dimensions.
let left_new_type = inner_array_type(*left_type.to_owned(), left_dim_owned);
let right_new_type = inner_array_type(*right_type.to_owned(), right_dim_owned);
let left_new_type = inner_array_type(*left_type.to_owned(), left_dims);
let right_new_type = inner_array_type(*right_type.to_owned(), right_dims);
// Call eq_flat() on the new left and right types.
left_new_type.eq_flat(&right_new_type)