Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for attributes on structs #2733

Merged
merged 8 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions compiler/noirc_frontend/src/ast/structure.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::fmt::Display;

use crate::{Ident, UnresolvedGenerics, UnresolvedType};
use crate::{token::SecondaryAttribute, Ident, UnresolvedGenerics, UnresolvedType};
use iter_extended::vecmap;
use noirc_errors::Span;

/// Ast node for a struct
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NoirStruct {
pub name: Ident,
pub attributes: Vec<SecondaryAttribute>,
pub generics: UnresolvedGenerics,
pub fields: Vec<(Ident, UnresolvedType)>,
pub span: Span,
Expand All @@ -16,11 +17,12 @@ pub struct NoirStruct {
impl NoirStruct {
pub fn new(
name: Ident,
attributes: Vec<SecondaryAttribute>,
generics: Vec<Ident>,
fields: Vec<(Ident, UnresolvedType)>,
span: Span,
) -> NoirStruct {
NoirStruct { name, generics, fields, span }
NoirStruct { name, attributes, generics, fields, span }
}
}

Expand Down
4 changes: 3 additions & 1 deletion compiler/noirc_frontend/src/parser/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ pub enum ParserErrorReason {
#[error("Where clauses are allowed only on functions with generic parameters")]
WhereClauseOnNonGenericFunction,
#[error(
"Multiple primary attributes found. Only one primary attribute is allowed per function."
"Multiple primary attributes found. Only one primary attribute is allowed per function"
)]
MultiplePrimaryAttributesFound,
#[error("A primary attribute cannot be placed on a struct")]
NoPrimaryAttributesAllowedOnStruct,
Maddiaa0 marked this conversation as resolved.
Show resolved Hide resolved
#[error("Assert statements can only accept string literals")]
AssertMessageNotString,
}
Expand Down
48 changes: 41 additions & 7 deletions compiler/noirc_frontend/src/parser/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
};
use crate::lexer::Lexer;
use crate::parser::{force, ignore_then_commit, statement_recovery};
use crate::token::{Attribute, Attributes, Keyword, Token, TokenKind};
use crate::token::{Attribute, Attributes, Keyword, SecondaryAttribute, Token, TokenKind};
use crate::{
BinaryOp, BinaryOpKind, BlockExpression, ConstrainStatement, Distinctness, FunctionDefinition,
FunctionReturnType, Ident, IfExpression, InfixExpression, LValue, Lambda, Literal,
Expand Down Expand Up @@ -237,11 +237,16 @@
),
);

keyword(Struct).ignore_then(ident()).then(generics()).then(fields).map_with_span(
|((name, generics), fields), span| {
TopLevelStatement::Struct(NoirStruct { name, generics, fields, span })
},
)
attributes()
.or_not()
.then_ignore(keyword(Struct))
.then(ident())
.then(generics())
.then(fields)
.validate(|(((raw_attributes, name), generics), fields), span, emit| {
let attributes = validate_struct_attributes(raw_attributes, span, emit);
TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span })
})
}

fn type_alias_definition() -> impl NoirParser<TopLevelStatement> {
Expand Down Expand Up @@ -340,10 +345,10 @@
}

fn self_parameter() -> impl NoirParser<(Pattern, UnresolvedType, Visibility)> {
let refmut_pattern = just(Token::Ampersand).then_ignore(keyword(Keyword::Mut));

Check warning on line 348 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (refmut)
let mut_pattern = keyword(Keyword::Mut);

refmut_pattern

Check warning on line 351 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (refmut)
.or(mut_pattern)
.map_with_span(|token, span| (token, span))
.or_not()
Expand Down Expand Up @@ -457,6 +462,29 @@
Attributes { primary, secondary }
}

fn validate_struct_attributes(
attributes: Option<Vec<Attribute>>,
span: Span,
emit: &mut dyn FnMut(ParserError),
) -> Vec<SecondaryAttribute> {
let attrs = attributes.unwrap_or_default();
let mut struct_attributes = vec![];

for attribute in attrs {
match attribute {
Attribute::Primary(..) => {
emit(ParserError::with_reason(
ParserErrorReason::NoPrimaryAttributesAllowedOnStruct,
span,
));
}
Attribute::Secondary(attr) => struct_attributes.push(attr),
}
}

struct_attributes
}

fn validate_where_clause(
generics: &Vec<Ident>,
where_clause: &Vec<TraitConstraint>,
Expand Down Expand Up @@ -888,7 +916,7 @@
let shorthand_operators = right_shift_operator().or(one_of(shorthand_operators));
let shorthand_syntax = shorthand_operators.then_ignore(just(Token::Assign));

// Since >> is lexed as two separate greater-thans, >>= is lexed as > >=, so

Check warning on line 919 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (thans)
// we need to account for that case here as well.
let right_shift_fix =
just(Token::Greater).then(just(Token::GreaterEqual)).map(|_| Token::ShiftRight);
Expand Down Expand Up @@ -916,7 +944,7 @@

let dereferences = just(Token::Star).repeated();

let lvalues =

Check warning on line 947 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (lvalues)
l_ident.then(l_member_rhs.or(l_index).repeated()).foldl(|lvalue, rhs| match rhs {
LValueRhs::MemberAccess(field_name) => {
LValue::MemberAccess { object: Box::new(lvalue), field_name }
Expand All @@ -924,7 +952,7 @@
LValueRhs::Index(index) => LValue::Index { array: Box::new(lvalue), index },
});

dereferences.then(lvalues).foldr(|_, lvalue| LValue::Dereference(Box::new(lvalue)))

Check warning on line 955 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (lvalues)

Check warning on line 955 in compiler/noirc_frontend/src/parser/parser.rs

View workflow job for this annotation

GitHub Actions / Spellcheck / Spellcheck

Unknown word (foldr)
}

fn parse_type<'a>() -> impl NoirParser<UnresolvedType> + 'a {
Expand Down Expand Up @@ -2218,10 +2246,16 @@
"struct Foo { }",
"struct Bar { ident: Field, }",
"struct Baz { ident: Field, other: Field }",
"#[attribute] struct Baz { ident: Field, other: Field }",
];
parse_all(struct_definition(), cases);

let failing = vec!["struct { }", "struct Foo { bar: pub Field }"];
let failing = vec![
"struct { }",
"struct Foo { bar: pub Field }",
"struct Foo { bar: pub Field }",
"#[oracle(some)] struct Foo { bar: Field }",
];
parse_all_failing(struct_definition(), failing);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

[package]
name = "primary_attribute_struct"
type = "bin"
authors = [""]
compiler_version = "0.11.1"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// An primary attribute should not be able to be added to a struct defintion
#[oracle(some_oracle)]
struct SomeStruct{
x: Field,
y: Field
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "attributes_struct"
type = "bin"
authors = [""]
compiler_version = "0.11.1"

[dependencies]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[some_attribute]
#[another_attribute]
struct SomeStruct {
a: Field,
b: Field
}

fn main() {}