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: Parser and formatter support for enums #7110

Merged
merged 7 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
50 changes: 50 additions & 0 deletions compiler/noirc_frontend/src/ast/enumeration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use std::fmt::Display;

use crate::ast::{Ident, UnresolvedGenerics, UnresolvedType};
use crate::token::SecondaryAttribute;

use iter_extended::vecmap;
use noirc_errors::Span;

use super::{Documented, ItemVisibility};

/// Ast node for an enum
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct NoirEnumeration {
pub name: Ident,
pub attributes: Vec<SecondaryAttribute>,
pub visibility: ItemVisibility,
pub generics: UnresolvedGenerics,
pub variants: Vec<Documented<EnumVariant>>,
pub span: Span,
}

impl NoirEnumeration {
pub fn is_abi(&self) -> bool {
self.attributes.iter().any(|attr| attr.is_abi())
}
}

/// We only support variants of the form `Name(A, B, ...)` currently.
/// Enum variants like `Name { a: A, b: B, .. }` will be implemented later
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EnumVariant {
pub name: Ident,
pub parameters: Vec<UnresolvedType>,
}

impl Display for NoirEnumeration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let generics = vecmap(&self.generics, |generic| generic.to_string());
let generics = if generics.is_empty() { "".into() } else { generics.join(", ") };

writeln!(f, "enum {}{} {{", self.name, generics)?;

for variant in self.variants.iter() {
let parameters = vecmap(&variant.item.parameters, ToString::to_string).join(", ");
writeln!(f, " {}({}),", variant.item.name, parameters)?;
}

write!(f, "}}")
}
}
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//! Noir's Ast is produced by the parser and taken as input to name resolution,
//! where it is converted into the Hir (defined in the hir_def module).
mod docs;
mod enumeration;
mod expression;
mod function;
mod statement;
Expand All @@ -24,6 +25,7 @@

use acvm::FieldElement;
pub use docs::*;
pub use enumeration::*;
use noirc_errors::Span;
use serde::{Deserialize, Serialize};
pub use statement::*;
Expand Down Expand Up @@ -601,7 +603,7 @@
Self::Public => write!(f, "pub"),
Self::Private => write!(f, "priv"),
Self::CallData(id) => write!(f, "calldata{id}"),
Self::ReturnData => write!(f, "returndata"),

Check warning on line 606 in compiler/noirc_frontend/src/ast/mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (returndata)
}
}
}
33 changes: 30 additions & 3 deletions compiler/noirc_frontend/src/ast/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@
};

use super::{
ForBounds, FunctionReturnType, GenericTypeArgs, IntegerBitSize, ItemVisibility, Pattern,
Signedness, TraitBound, TraitImplItemKind, TypePath, UnresolvedGenerics,
UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression,
ForBounds, FunctionReturnType, GenericTypeArgs, IntegerBitSize, ItemVisibility,
NoirEnumeration, Pattern, Signedness, TraitBound, TraitImplItemKind, TypePath,
UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData,
UnresolvedTypeExpression,
};

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum AttributeTarget {
Module,
Struct,
Enum,
Trait,
Function,
Let,
Expand Down Expand Up @@ -142,6 +144,10 @@
true
}

fn visit_noir_enum(&mut self, _: &NoirEnumeration, _: Span) -> bool {
true
}

fn visit_noir_type_alias(&mut self, _: &NoirTypeAlias, _: Span) -> bool {
true
}
Expand Down Expand Up @@ -527,6 +533,7 @@
}
ItemKind::TypeAlias(noir_type_alias) => noir_type_alias.accept(self.span, visitor),
ItemKind::Struct(noir_struct) => noir_struct.accept(self.span, visitor),
ItemKind::Enum(noir_enum) => noir_enum.accept(self.span, visitor),
ItemKind::ModuleDecl(module_declaration) => {
module_declaration.accept(self.span, visitor);
}
Expand Down Expand Up @@ -775,6 +782,26 @@
}
}

impl NoirEnumeration {
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
if visitor.visit_noir_enum(self, span) {
self.accept_children(visitor);
}
}

pub fn accept_children(&self, visitor: &mut impl Visitor) {
for attribute in &self.attributes {
attribute.accept(AttributeTarget::Enum, visitor);
}

for variant in &self.variants {
for parameter in &variant.item.parameters {
parameter.accept(visitor);
}
}
}
}

impl NoirTypeAlias {
pub fn accept(&self, span: Span, visitor: &mut impl Visitor) {
if visitor.visit_noir_type_alias(self, span) {
Expand Down Expand Up @@ -1331,8 +1358,8 @@
UnresolvedTypeData::Unspecified => visitor.visit_unspecified_type(self.span),
UnresolvedTypeData::Quoted(typ) => visitor.visit_quoted_type(typ, self.span),
UnresolvedTypeData::FieldElement => visitor.visit_field_element_type(self.span),
UnresolvedTypeData::Integer(signdness, size) => {

Check warning on line 1361 in compiler/noirc_frontend/src/ast/visitor.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (signdness)
visitor.visit_integer_type(*signdness, *size, self.span);

Check warning on line 1362 in compiler/noirc_frontend/src/ast/visitor.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (signdness)
}
UnresolvedTypeData::Bool => visitor.visit_bool_type(self.span),
UnresolvedTypeData::Unit => visitor.visit_unit_type(self.span),
Expand Down
16 changes: 15 additions & 1 deletion compiler/noirc_frontend/src/elaborator/comptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,21 @@ impl<'context> Elaborator<'context> {
self.crate_id,
&mut self.errors,
) {
generated_items.types.insert(type_id, the_struct);
generated_items.structs.insert(type_id, the_struct);
}
}
ItemKind::Enum(enum_def) => {
if let Some((type_id, the_enum)) = dc_mod::collect_enum(
self.interner,
self.def_maps.get_mut(&self.crate_id).unwrap(),
self.usage_tracker,
Documented::new(enum_def, item.doc_comments),
self.file,
self.local_module,
self.crate_id,
&mut self.errors,
) {
generated_items.enums.insert(type_id, the_enum);
}
}
ItemKind::Impl(r#impl) => {
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/elaborator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl<'context> Elaborator<'context> {
}

// Must resolve structs before we resolve globals.
self.collect_struct_definitions(&items.types);
self.collect_struct_definitions(&items.structs);

self.define_function_metas(&mut items.functions, &mut items.impls, &mut items.trait_impls);

Expand Down Expand Up @@ -349,7 +349,7 @@ impl<'context> Elaborator<'context> {
// since the generated items are checked beforehand as well.
self.run_attributes(
&items.traits,
&items.types,
&items.structs,
&items.functions,
&items.module_attributes,
);
Expand Down
16 changes: 12 additions & 4 deletions compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{Generics, Type};
use crate::hir::resolution::import::{resolve_import, ImportDirective};
use crate::hir::Context;

use crate::ast::Expression;
use crate::ast::{Expression, NoirEnumeration};
use crate::node_interner::{
FuncId, GlobalId, ModuleAttributes, NodeInterner, ReferenceId, StructId, TraitId, TraitImplId,
TypeAliasId,
Expand Down Expand Up @@ -64,6 +64,12 @@ pub struct UnresolvedStruct {
pub struct_def: NoirStruct,
}

pub struct UnresolvedEnum {
pub file_id: FileId,
pub module_id: LocalModuleId,
pub enum_def: NoirEnumeration,
}

#[derive(Clone)]
pub struct UnresolvedTrait {
pub file_id: FileId,
Expand Down Expand Up @@ -141,7 +147,8 @@ pub struct DefCollector {
#[derive(Default)]
pub struct CollectedItems {
pub functions: Vec<UnresolvedFunctions>,
pub(crate) types: BTreeMap<StructId, UnresolvedStruct>,
pub(crate) structs: BTreeMap<StructId, UnresolvedStruct>,
pub(crate) enums: BTreeMap<StructId, UnresolvedEnum>,
pub(crate) type_aliases: BTreeMap<TypeAliasId, UnresolvedTypeAlias>,
pub(crate) traits: BTreeMap<TraitId, UnresolvedTrait>,
pub globals: Vec<UnresolvedGlobal>,
Expand All @@ -153,7 +160,7 @@ pub struct CollectedItems {
impl CollectedItems {
pub fn is_empty(&self) -> bool {
self.functions.is_empty()
&& self.types.is_empty()
&& self.structs.is_empty()
&& self.type_aliases.is_empty()
&& self.traits.is_empty()
&& self.globals.is_empty()
Expand Down Expand Up @@ -254,7 +261,8 @@ impl DefCollector {
imports: vec![],
items: CollectedItems {
functions: vec![],
types: BTreeMap::new(),
structs: BTreeMap::new(),
enums: BTreeMap::new(),
type_aliases: BTreeMap::new(),
traits: BTreeMap::new(),
impls: HashMap::default(),
Expand Down
25 changes: 20 additions & 5 deletions compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@

use crate::ast::{
Documented, Expression, FunctionDefinition, Ident, ItemVisibility, LetStatement,
ModuleDeclaration, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Pattern,
TraitImplItemKind, TraitItem, TypeImpl, UnresolvedType, UnresolvedTypeData,
ModuleDeclaration, NoirEnumeration, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl,
NoirTypeAlias, Pattern, TraitImplItemKind, TraitItem, TypeImpl, UnresolvedType,
UnresolvedTypeData,
};
use crate::hir::resolution::errors::ResolverError;
use crate::node_interner::{ModuleAttributes, NodeInterner, ReferenceId, StructId};
Expand All @@ -27,8 +28,8 @@
};
use crate::{Generics, Kind, ResolvedGeneric, Type, TypeVariable};

use super::dc_crate::CollectedItems;
use super::dc_crate::ModuleAttribute;
use super::dc_crate::{CollectedItems, UnresolvedEnum};
use super::{
dc_crate::{
CompilationError, DefCollector, UnresolvedFunctions, UnresolvedGlobal, UnresolvedTraitImpl,
Expand Down Expand Up @@ -91,7 +92,7 @@

errors.extend(collector.collect_traits(context, ast.traits, crate_id));

errors.extend(collector.collect_structs(context, ast.types, crate_id));
errors.extend(collector.collect_structs(context, ast.structs, crate_id));

errors.extend(collector.collect_type_aliases(context, ast.type_aliases, crate_id));

Expand Down Expand Up @@ -317,7 +318,7 @@
krate,
&mut definition_errors,
) {
self.def_collector.items.types.insert(id, the_struct);
self.def_collector.items.structs.insert(id, the_struct);
}
}
definition_errors
Expand Down Expand Up @@ -874,7 +875,7 @@
// if it's an inline module, or the first char of a the file if it's an external module.
// - `location` will always point to the token "foo" in `mod foo` regardless of whether
// it's inline or external.
// Eventually the location put in `ModuleData` is used for codelenses about `contract`s,

Check warning on line 878 in compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (codelenses)
// so we keep using `location` so that it continues to work as usual.
let location = Location::new(mod_name.span(), mod_location.file);
let new_module = ModuleData::new(
Expand Down Expand Up @@ -1078,6 +1079,20 @@
Some((id, unresolved))
}

#[allow(clippy::too_many_arguments)]
pub fn collect_enum(
_interner: &mut NodeInterner,
_def_map: &mut CrateDefMap,
_usage_tracker: &mut UsageTracker,
_enum_definition: Documented<NoirEnumeration>,
_file_id: FileId,
_module_id: LocalModuleId,
_krate: CrateId,
_definition_errors: &mut [(CompilationError, FileId)],
) -> Option<(StructId, UnresolvedEnum)> {
todo!("Implement collect_enum")
}

pub fn collect_impl(
interner: &mut NodeInterner,
items: &mut CollectedItems,
Expand Down
2 changes: 2 additions & 0 deletions compiler/noirc_frontend/src/hir_def/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@
Type,
TypedExpr,
StructDefinition,
EnumDefinition,
TraitConstraint,
TraitDefinition,
TraitImpl,
Expand Down Expand Up @@ -955,6 +956,7 @@
QuotedType::Type => write!(f, "Type"),
QuotedType::TypedExpr => write!(f, "TypedExpr"),
QuotedType::StructDefinition => write!(f, "StructDefinition"),
QuotedType::EnumDefinition => write!(f, "EnumDefinition"),
QuotedType::TraitDefinition => write!(f, "TraitDefinition"),
QuotedType::TraitConstraint => write!(f, "TraitConstraint"),
QuotedType::TraitImpl => write!(f, "TraitImpl"),
Expand Down Expand Up @@ -2197,7 +2199,7 @@
Type::Slice(element) => {
let element = element.substitute_helper(type_bindings, substitute_bound_typevars);
Type::Slice(Box::new(element))
}

Check warning on line 2202 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (recuring)
Type::String(size) => {
let size = size.substitute_helper(type_bindings, substitute_bound_typevars);
Type::String(Box::new(size))
Expand Down Expand Up @@ -2283,7 +2285,7 @@
}
}

/// True if the given TypeVariableId is free anywhere within self

Check warning on line 2288 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevarsfined)
pub fn occurs(&self, target_id: TypeVariableId) -> bool {
match self {
Type::Array(len, elem) => len.occurs(target_id) || elem.occurs(target_id),
Expand Down Expand Up @@ -2449,7 +2451,7 @@
Type::Tuple(fields) => {
for field in fields {
field.replace_named_generics_with_type_variables();
}

Check warning on line 2454 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (typevariable)
}
Type::Struct(_, generics) => {
for generic in generics {
Expand All @@ -2470,7 +2472,7 @@
}
}
Type::TraitAsType(_, _, generics) => {
for generic in &mut generics.ordered {

Check warning on line 2475 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (unbindable)
generic.replace_named_generics_with_type_variables();
}
for generic in &mut generics.named {
Expand Down Expand Up @@ -2931,7 +2933,7 @@
if let TypeBinding::Bound(typ) = &*variable.borrow() {
return typ == other;
}
}

Check warning on line 2936 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)

Check warning on line 2936 in compiler/noirc_frontend/src/hir_def/types.rs

View workflow job for this annotation

GitHub Actions / Code

Unknown word (elems)

if let Some((variable, other_kind)) = other.get_inner_type_variable() {
if self.kind() != other_kind {
Expand Down
3 changes: 3 additions & 0 deletions compiler/noirc_frontend/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,7 @@ pub enum Keyword {
Dep,
Else,
Enum,
EnumDefinition,
Expr,
Field,
Fn,
Expand Down Expand Up @@ -1080,6 +1081,7 @@ impl fmt::Display for Keyword {
Keyword::Dep => write!(f, "dep"),
Keyword::Else => write!(f, "else"),
Keyword::Enum => write!(f, "enum"),
Keyword::EnumDefinition => write!(f, "EnumDefinition"),
Keyword::Expr => write!(f, "Expr"),
Keyword::Field => write!(f, "Field"),
Keyword::Fn => write!(f, "fn"),
Expand Down Expand Up @@ -1143,6 +1145,7 @@ impl Keyword {
"dep" => Keyword::Dep,
"else" => Keyword::Else,
"enum" => Keyword::Enum,
"EnumDefinition" => Keyword::EnumDefinition,
"Expr" => Keyword::Expr,
"Field" => Keyword::Field,
"fn" => Keyword::Fn,
Expand Down
4 changes: 2 additions & 2 deletions compiler/noirc_frontend/src/parser/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ pub enum ParserErrorReason {
"Multiple primary attributes found. Only one function attribute is allowed per function"
)]
MultipleFunctionAttributesFound,
#[error("A function attribute cannot be placed on a struct")]
NoFunctionAttributesAllowedOnStruct,
#[error("A function attribute cannot be placed on a struct or enum")]
NoFunctionAttributesAllowedOnType,
#[error("Assert statements can only accept string literals")]
AssertMessageNotString,
#[error("Integer bit size {0} isn't supported")]
Expand Down
Loading
Loading