Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
48 changes: 40 additions & 8 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ use builtin_helpers::{
get_format_string, get_function_def, get_module, get_quoted, get_slice, get_struct,
get_trait_constraint, get_trait_def, get_trait_impl, get_tuple, get_type, get_typed_expr,
get_u32, get_unresolved_type, has_named_attribute, hir_pattern_to_tokens,
mutate_func_meta_type, parse, replace_func_meta_parameters, replace_func_meta_return_type,
mutate_func_meta_type, parse, quote_ident, quote_path, replace_func_meta_parameters,
replace_func_meta_return_type,
};
use chumsky::{chain::Chain, prelude::choice, Parser};
use im::Vector;
Expand Down Expand Up @@ -72,6 +73,9 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"expr_as_bool" => expr_as_bool(interner, arguments, return_type, location),
"expr_as_cast" => expr_as_cast(interner, arguments, return_type, location),
"expr_as_comptime" => expr_as_comptime(interner, arguments, return_type, location),
"expr_as_constructor" => {
expr_as_constructor(interner, arguments, return_type, location)
}
"expr_as_function_call" => {
expr_as_function_call(interner, arguments, return_type, location)
}
Expand Down Expand Up @@ -1404,6 +1408,38 @@ fn expr_as_comptime(
})
}

// fn as_constructor(self) -> Option<(Quoted, [(Quoted, Expr)])>
fn expr_as_constructor(
interner: &mut NodeInterner,
arguments: Vec<(Value, Location)>,
return_type: Type,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let expr_value = get_expr(interner, self_argument)?;
let expr_value = unwrap_expr_value(interner, expr_value);

let option_value =
if let ExprValue::Expression(ExpressionKind::Constructor(constructor)) = expr_value {
let typ = quote_path(&constructor.type_name, interner);
let fields = constructor.fields.into_iter();
let fields = fields.map(|(name, value)| {
Value::Tuple(vec![quote_ident(&name), Value::expression(value.kind)])
});
let fields = fields.collect();
let fields_type = Type::Slice(Box::new(Type::Tuple(vec![
Type::Quoted(QuotedType::Quoted),
Type::Quoted(QuotedType::Expr),
])));
let fields = Value::Slice(fields, fields_type);
Some(Value::Tuple(vec![typ, fields]))
} else {
None
};

option(return_type, option_value)
}

// fn as_function_call(self) -> Option<(Expr, [Expr])>
fn expr_as_function_call(
interner: &NodeInterner,
Expand Down Expand Up @@ -1545,15 +1581,13 @@ fn expr_as_member_access(
) -> IResult<Value> {
expr_as(interner, arguments, return_type, location, |expr| match expr {
ExprValue::Expression(ExpressionKind::MemberAccess(member_access)) => {
let tokens = Rc::new(vec![Token::Ident(member_access.rhs.0.contents.clone())]);
Some(Value::Tuple(vec![
Value::expression(member_access.lhs.kind),
Value::Quoted(tokens),
quote_ident(&member_access.rhs),
]))
}
ExprValue::LValue(crate::ast::LValue::MemberAccess { object, field_name, span: _ }) => {
let tokens = Rc::new(vec![Token::Ident(field_name.0.contents.clone())]);
Some(Value::Tuple(vec![Value::lvalue(*object), Value::Quoted(tokens)]))
Some(Value::Tuple(vec![Value::lvalue(*object), quote_ident(&field_name)]))
}
_ => None,
})
Expand All @@ -1570,9 +1604,7 @@ fn expr_as_method_call(
if let ExprValue::Expression(ExpressionKind::MethodCall(method_call)) = expr {
let object = Value::expression(method_call.object.kind);

let name_tokens =
Rc::new(vec![Token::Ident(method_call.method_name.0.contents.clone())]);
let name = Value::Quoted(name_tokens);
let name = quote_ident(&method_call.method_name);

let generics = method_call.generics.unwrap_or_default().into_iter();
let generics = generics.map(|generic| Value::UnresolvedType(generic.typ)).collect();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use noirc_errors::Location;

use crate::{
ast::{
BlockExpression, ExpressionKind, IntegerBitSize, LValue, Pattern, Signedness,
BlockExpression, ExpressionKind, Ident, IntegerBitSize, LValue, Path, Pattern, Signedness,
StatementKind, UnresolvedTypeData,
},
elaborator::Elaborator,
Expand Down Expand Up @@ -471,3 +471,38 @@ pub(super) fn has_named_attribute<'a>(

false
}

pub(super) fn quote_ident(ident: &Ident) -> Value {
Value::Quoted(ident_to_tokens(ident))
}

pub(super) fn ident_to_tokens(ident: &Ident) -> Rc<Vec<Token>> {
Rc::new(vec![Token::Ident(ident.0.contents.clone())])
}

pub(super) fn quote_path(path: &Path, interner: &mut NodeInterner) -> Value {
Value::Quoted(path_to_tokens(path, interner))
}

pub(super) fn path_to_tokens(path: &Path, interner: &mut NodeInterner) -> Rc<Vec<Token>> {
let mut tokens = Vec::new();
for (index, segment) in path.segments.iter().enumerate() {
if index > 0 {
tokens.push(Token::DoubleColon);
}
tokens.push(Token::Ident(segment.ident.0.contents.clone()));
if let Some(generics) = &segment.generics {
tokens.push(Token::DoubleColon);
tokens.push(Token::Less);
for (index, generic) in generics.iter().enumerate() {
if index > 0 {
tokens.push(Token::Comma);
}
let id = interner.push_unresolved_type_data(generic.typ.clone());
tokens.push(Token::InternedUnresolvedTypeData(id));
}
tokens.push(Token::Greater);
}
}
Rc::new(tokens)
}
14 changes: 14 additions & 0 deletions docs/docs/noir/standard_library/meta/expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,27 @@ a slice containing each statement.

If this expression is a boolean literal, return that literal.

### as_cast

#include_code as_cast noir_stdlib/src/meta/expr.nr rust

If this expression is a cast expression (`expr as type`), returns the casted
expression and the type to cast to.

### as_comptime

#include_code as_comptime noir_stdlib/src/meta/expr.nr rust

If this expression is a `comptime { stmt1; stmt2; ...; stmtN }` block,
return each statement in the block.

### as_constructor

#include_code as_constructor noir_stdlib/src/meta/expr.nr rust

If this expression is a constructor `Type { field1: expr1, ..., fieldN: exprN }`,
return the type and the fields.

### as_function_call

#include_code as_function_call noir_stdlib/src/meta/expr.nr rust
Expand Down
Loading