Skip to content

Commit

Permalink
Merge da830ae into 34f21c0
Browse files Browse the repository at this point in the history
  • Loading branch information
asterite authored Sep 4, 2024
2 parents 34f21c0 + da830ae commit fca865c
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 34 deletions.
14 changes: 13 additions & 1 deletion compiler/noirc_frontend/src/hir/comptime/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,19 @@ impl<'local, 'interner> Interpreter<'local, 'interner> {
consuming = false;

if let Some(value) = values.pop_front() {
result.push_str(&value.display(self.elaborator.interner).to_string());
// When interpolating a quoted value inside a format string, we don't include the
// surrounding `quote {` ... `}` as if we are unquoting the quoted value inside the string.
if let Value::Quoted(tokens) = value {
for (index, token) in tokens.iter().enumerate() {
if index > 0 {
result.push(' ');
}
result
.push_str(&token.display(self.elaborator.interner).to_string());
}
} else {
result.push_str(&value.display(self.elaborator.interner).to_string());
}
}
}
other if !consuming => {
Expand Down
25 changes: 22 additions & 3 deletions compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use acvm::{AcirField, FieldElement};
use builtin_helpers::{
block_expression_to_value, check_argument_count, check_function_not_yet_resolved,
check_one_argument, check_three_arguments, check_two_arguments, get_expr, get_field,
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, hir_pattern_to_tokens, mutate_func_meta_type, parse,
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, hir_pattern_to_tokens, mutate_func_meta_type, parse,
replace_func_meta_parameters, replace_func_meta_return_type,
};
use chumsky::{prelude::choice, Parser};
Expand All @@ -32,6 +32,7 @@ use crate::{
InterpreterError, Value,
},
hir_def::function::FunctionBody,
lexer::Lexer,
macros_api::{HirExpression, HirLiteral, ModuleDefId, NodeInterner, Signedness},
node_interner::{DefinitionKind, TraitImplKind},
parser::{self},
Expand Down Expand Up @@ -95,6 +96,7 @@ impl<'local, 'context> Interpreter<'local, 'context> {
"expr_is_continue" => expr_is_continue(interner, arguments, location),
"expr_resolve" => expr_resolve(self, arguments, location),
"is_unconstrained" => Ok(Value::Bool(true)),
"fmtstr_quoted_contents" => fmtstr_quoted_contents(interner, arguments, location),
"function_def_body" => function_def_body(interner, arguments, location),
"function_def_has_named_attribute" => {
function_def_has_named_attribute(interner, arguments, location)
Expand Down Expand Up @@ -1576,6 +1578,23 @@ fn unwrap_expr_value(interner: &NodeInterner, mut expr_value: ExprValue) -> Expr
expr_value
}

// fn quoted_contents(self) -> Quoted
fn fmtstr_quoted_contents(
interner: &NodeInterner,
arguments: Vec<(Value, Location)>,
location: Location,
) -> IResult<Value> {
let self_argument = check_one_argument(arguments, location)?;
let (string, _) = get_format_string(interner, self_argument)?;
let (tokens, _) = Lexer::lex(&string);
let mut tokens: Vec<_> = tokens.0.into_iter().map(|token| token.into_token()).collect();
if let Some(Token::EOF) = tokens.last() {
tokens.pop();
}

Ok(Value::Quoted(Rc::new(tokens)))
}

// fn body(self) -> Expr
fn function_def_body(
interner: &NodeInterner,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,20 @@ pub(crate) fn get_expr(
}
}

pub(crate) fn get_format_string(
interner: &NodeInterner,
(value, location): (Value, Location),
) -> IResult<(Rc<String>, Type)> {
match value {
Value::FormatString(value, typ) => Ok((value, typ)),
value => {
let n = Box::new(interner.next_type_variable());
let e = Box::new(interner.next_type_variable());
type_mismatch(value, Type::FmtString(n, e), location)
}
}
}

pub(crate) fn get_function_def((value, location): (Value, Location)) -> IResult<FuncId> {
match value {
Value::FunctionDefinition(id) => Ok(id),
Expand Down
73 changes: 46 additions & 27 deletions compiler/noirc_frontend/src/hir/comptime/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -605,33 +605,7 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> {
write!(f, "quote {{")?;
for token in tokens.iter() {
write!(f, " ")?;

match token {
Token::QuotedType(id) => {
write!(f, "{}", self.interner.get_quoted_type(*id))?;
}
Token::InternedExpr(id) => {
let value = Value::expression(ExpressionKind::Interned(*id));
value.display(self.interner).fmt(f)?;
}
Token::InternedStatement(id) => {
let value = Value::statement(StatementKind::Interned(*id));
value.display(self.interner).fmt(f)?;
}
Token::InternedLValue(id) => {
let value = Value::lvalue(LValue::Interned(*id, Span::default()));
value.display(self.interner).fmt(f)?;
}
Token::InternedUnresolvedTypeData(id) => {
let value = Value::UnresolvedType(UnresolvedTypeData::Interned(*id));
value.display(self.interner).fmt(f)?;
}
Token::UnquoteMarker(id) => {
let value = Value::TypedExpr(TypedExpr::ExprId(*id));
value.display(self.interner).fmt(f)?;
}
other => write!(f, "{other}")?,
}
token.display(self.interner).fmt(f)?;
}
write!(f, " }}")
}
Expand Down Expand Up @@ -713,6 +687,51 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> {
}
}

impl Token {
pub fn display<'token, 'interner>(
&'token self,
interner: &'interner NodeInterner,
) -> TokenPrinter<'token, 'interner> {
TokenPrinter { token: self, interner }
}
}

pub struct TokenPrinter<'token, 'interner> {
token: &'token Token,
interner: &'interner NodeInterner,
}

impl<'token, 'interner> Display for TokenPrinter<'token, 'interner> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.token {
Token::QuotedType(id) => {
write!(f, "{}", self.interner.get_quoted_type(*id))
}
Token::InternedExpr(id) => {
let value = Value::expression(ExpressionKind::Interned(*id));
value.display(self.interner).fmt(f)
}
Token::InternedStatement(id) => {
let value = Value::statement(StatementKind::Interned(*id));
value.display(self.interner).fmt(f)
}
Token::InternedLValue(id) => {
let value = Value::lvalue(LValue::Interned(*id, Span::default()));
value.display(self.interner).fmt(f)
}
Token::InternedUnresolvedTypeData(id) => {
let value = Value::UnresolvedType(UnresolvedTypeData::Interned(*id));
value.display(self.interner).fmt(f)
}
Token::UnquoteMarker(id) => {
let value = Value::TypedExpr(TypedExpr::ExprId(*id));
value.display(self.interner).fmt(f)
}
other => write!(f, "{other}"),
}
}
}

fn display_trait_constraint(interner: &NodeInterner, trait_constraint: &TraitConstraint) -> String {
let trait_ = interner.get_trait(trait_constraint.trait_id);
format!("{}: {}{}", trait_constraint.typ, trait_.name, trait_constraint.trait_generics)
Expand Down
13 changes: 13 additions & 0 deletions docs/docs/noir/standard_library/fmtstr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: fmtstr
---

`fmtstr<N, T>` is the type resulting from using format string (`f"..."`).

## Methods

### quoted_contents

#include_code quoted_contents noir_stdlib/src/meta/format_string.nr rust

Returns the format string contents (that is, without the leading and trailing double quotes) as a `Quoted` value.
6 changes: 6 additions & 0 deletions noir_stdlib/src/meta/format_string.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
impl <let N: u32, T> fmtstr<N, T> {
#[builtin(fmtstr_quoted_contents)]
// docs:start:quoted_contents
fn quoted_contents(self) -> Quoted {}
// docs:end:quoted_contents
}
1 change: 1 addition & 0 deletions noir_stdlib/src/meta/mod.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod expr;
mod format_string;
mod function_def;
mod module;
mod op;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,18 @@ fn main() {
};
assert_eq(s1, "x is 4, fake interpolation: {y}, y is 5");
assert_eq(s2, "\0\0\0\0");

// Mainly test fmtstr::quoted_contents
call!(glue(quote { hello }, quote { world }));
}

fn glue(x: Quoted, y: Quoted) -> Quoted {
f"{x}_{y}".quoted_contents()
}

fn hello_world() {}

comptime fn call(x: Quoted) -> Quoted {
quote { $x() }
}

Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ fn foo(x: Field, y: u32) -> u32 {

// Given a function, wrap its parameters in a struct definition
comptime fn output_struct(f: FunctionDefinition) -> Quoted {
let fields = f.parameters().map(|param: (Quoted, Type)| {
let fields = f.parameters().map(
|param: (Quoted, Type)| {
let name = param.0;
let typ = param.1;
quote { $name: $typ, }
}).join(quote {});
}
).join(quote {});

quote {
struct Foo { $fields }
Expand Down
2 changes: 1 addition & 1 deletion tooling/lsp/src/requests/completion/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ mod completion_tests {
fo>|<
}
"#;
assert_completion(src, vec![module_completion_item("foobar")]).await;
assert_completion_excluding_auto_import(src, vec![module_completion_item("foobar")]).await;
}

#[test]
Expand Down

0 comments on commit fca865c

Please sign in to comment.