From d1bf92f99e37463ea71a44899083f45a9c903aa7 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 5 Sep 2024 14:02:16 -0300 Subject: [PATCH 1/2] Add FunctionDefinition::add_attribute --- .../noirc_frontend/src/hir/comptime/errors.rs | 10 ++++ .../src/hir/comptime/interpreter/builtin.rs | 56 ++++++++++++++++++- noir_stdlib/src/meta/function_def.nr | 5 ++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/errors.rs b/compiler/noirc_frontend/src/hir/comptime/errors.rs index f6585786eeb..5d4d814f3ee 100644 --- a/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -207,6 +207,10 @@ pub enum InterpreterError { index: usize, location: Location, }, + InvalidAttribute { + attribute: String, + location: Location, + }, // These cases are not errors, they are just used to prevent us from running more code // until the loop can be resumed properly. These cases will never be displayed to users. @@ -276,6 +280,7 @@ impl InterpreterError { | InterpreterError::MultipleMatchingImpls { location, .. } | InterpreterError::ExpectedIdentForStructField { location, .. } | InterpreterError::TypeAnnotationsNeededForMethodCall { location } => *location, + InterpreterError::InvalidAttribute { location, .. } => *location, InterpreterError::FailedToParseMacro { error, file, .. } => { Location::new(error.span(), *file) @@ -579,6 +584,11 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { let secondary = format!("`{value}` is not a valid field name for `set_fields`"); CustomDiagnostic::simple_error(msg, secondary, location.span) } + InterpreterError::InvalidAttribute { attribute, location } => { + let msg = format!("`{attribute}` is not a valid attribute"); + let secondary = "Note that this method expects attribute contents, without the leading `#[` or trailing `]`".to_string(); + CustomDiagnostic::simple_error(msg, secondary, location.span) + } } } } diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 65c9c3f018d..5e0aad00045 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -12,7 +12,7 @@ use builtin_helpers::{ get_u32, get_unresolved_type, hir_pattern_to_tokens, mutate_func_meta_type, parse, replace_func_meta_parameters, replace_func_meta_return_type, }; -use chumsky::{prelude::choice, Parser}; +use chumsky::{chain::Chain, prelude::choice, Parser}; use im::Vector; use iter_extended::{try_vecmap, vecmap}; use noirc_errors::Location; @@ -36,7 +36,7 @@ use crate::{ macros_api::{HirExpression, HirLiteral, Ident, ModuleDefId, NodeInterner, Signedness}, node_interner::{DefinitionKind, TraitImplKind}, parser::{self}, - token::Token, + token::{Attribute, SecondaryAttribute, Token}, QuotedType, Shared, Type, }; @@ -97,6 +97,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "expr_resolve" => expr_resolve(self, arguments, location), "is_unconstrained" => Ok(Value::Bool(true)), "fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location), + "function_def_add_attribute" => function_def_add_attribute(self, arguments, location), "function_def_body" => function_def_body(interner, arguments, location), "function_def_has_named_attribute" => { function_def_has_named_attribute(interner, arguments, location) @@ -1654,6 +1655,57 @@ fn fmtstr_quoted_contents( Ok(Value::Quoted(Rc::new(tokens))) } +// fn add_attribute(self, attribute: str) +fn function_def_add_attribute( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let (self_argument, attribute) = check_two_arguments(arguments, location)?; + let attribute_location = attribute.1; + let attribute = get_str(interpreter.elaborator.interner, attribute)?; + + let mut tokens = Lexer::lex(&format!("#[{}]", attribute)).0 .0; + if let Some(Token::EOF) = tokens.last().map(|token| token.token()) { + tokens.pop(); + } + if tokens.len() != 1 { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + } + + let token = tokens[0].token(); + let Token::Attribute(attribute) = token else { + return Err(InterpreterError::InvalidAttribute { + attribute: attribute.to_string(), + location: attribute_location, + }); + }; + + let func_id = get_function_def(self_argument)?; + check_function_not_yet_resolved(interpreter, func_id, location)?; + + let function_modifiers = interpreter.elaborator.interner.function_modifiers_mut(&func_id); + + match attribute { + Attribute::Function(attribute) => { + function_modifiers.attributes.function = Some(attribute.clone()); + } + Attribute::Secondary(attribute) => { + function_modifiers.attributes.secondary.push(attribute.clone()); + } + } + + if let Attribute::Secondary(SecondaryAttribute::Custom(attribute)) = attribute { + let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); + func_meta.custom_attributes.push(attribute.clone()); + } + + Ok(Value::Unit) +} + // fn body(self) -> Expr fn function_def_body( interner: &NodeInterner, diff --git a/noir_stdlib/src/meta/function_def.nr b/noir_stdlib/src/meta/function_def.nr index cbbbfb2f901..c1f2c026d57 100644 --- a/noir_stdlib/src/meta/function_def.nr +++ b/noir_stdlib/src/meta/function_def.nr @@ -1,4 +1,9 @@ impl FunctionDefinition { + #[builtin(function_def_add_attribute)] + // docs:start:add_attribute + fn add_attribute(self, attribute: str) {} + // docs:end:add_attribute + #[builtin(function_def_body)] // docs:start:body fn body(self) -> Expr {} From f919cd00626a7ad43539ddc235334bfc4fd09e8a Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Thu, 5 Sep 2024 14:23:11 -0300 Subject: [PATCH 2/2] Add docs --- docs/docs/noir/standard_library/meta/function_def.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/docs/noir/standard_library/meta/function_def.md b/docs/docs/noir/standard_library/meta/function_def.md index 5657e05fff7..3789fd82866 100644 --- a/docs/docs/noir/standard_library/meta/function_def.md +++ b/docs/docs/noir/standard_library/meta/function_def.md @@ -7,6 +7,14 @@ a function definition in the source program. ## Methods +### add_attribute + +#include_code add_attribute noir_stdlib/src/meta/function_def.nr rust + +Adds an attribute to the function. This is only valid +on functions in the current crate which have not yet been resolved. +This means any functions called at compile-time are invalid targets for this method. + ### body #include_code body noir_stdlib/src/meta/function_def.nr rust