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

Fix formatting of Quoted values #5899

Closed
asterite opened this issue Sep 3, 2024 · 4 comments · Fixed by #5896 or #5928
Closed

Fix formatting of Quoted values #5899

asterite opened this issue Sep 3, 2024 · 4 comments · Fixed by #5896 or #5928
Labels
enhancement New feature or request

Comments

@asterite
Copy link
Collaborator

asterite commented Sep 3, 2024

Problem

Unquoting inside string literals doesn't work

Happy Case

This should work:

fn main() {
    comptime {
        let x = 3;
        let q = quote { x is $x };
        assert(false, f"q = {q}");
    }
}

Right now it gives this error:

error: q = quote { x is (UnquoteMarker) }
  ┌─ src/main.nr:5:16
  │
5 │         assert(false, f"q = {q}");
  │                ----- Assertion failed
  │

Workaround

None

Workaround Description

No response

Additional Context

No response

Project Impact

None

Blocker Context

No response

Would you like to submit a PR for this Issue?

None

Support Needs

No response

@asterite asterite added the enhancement New feature or request label Sep 3, 2024
@jfecher
Copy link
Contributor

jfecher commented Sep 3, 2024

We don't need to allow unquoting inside string literals - you can use format strings to format them which the example shows. The error is only because of the assert(false, _) and is just meant to show that when Quoted values are turned to strings we don't recursively handle converting each token to a string with the interner. We just call .to_string() on all of them which gives us (UnquoteMarker) strings.

@jfecher jfecher changed the title Allow unquoting inside string literals Fix formatting of Quoted values Sep 3, 2024
@asterite
Copy link
Collaborator Author

asterite commented Sep 3, 2024

Ah, great! I didn't know if the issue was only about converting Quoted values to string. It seems #5899 fixes this, then.

github-merge-queue bot pushed a commit that referenced this issue Sep 3, 2024
# Description

## Problem

Resolves #5899

For debugging purposes, when you `println` a quoted value, some token
values aren't expanded, making it a bit harder to understand what's
going on.

## Summary

Now interned expressions are shown in `Quoted` values.

This program:

```rust
fn main() {
    comptime
    {
        let n = quote { [1, 2, 3] }.as_expr().unwrap();
        let q = quote { $n };
        println(q);
    }
}
```

Used to print:

```
quote { (expr) }
```

Now it prints: 

```
quote { [1, 2, 3] }
```

## Additional Context

None.

## Documentation

Check one:
- [x] No documentation needed.
- [ ] Documentation included in this PR.
- [ ] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
@asterite asterite reopened this Sep 4, 2024
@asterite
Copy link
Collaborator Author

asterite commented Sep 4, 2024

@jfecher I'm not sure this is solved.

For example this program:

fn main() {
    comptime
    {
        let name = quote { bar };
        assert_param(name);
    }
}

comptime fn assert_param(name: Quoted) {
    assert(false, f"Param {name} failed assertion");
}

Maybe I'd expect the output to be:

Param bar failed assertion

but right now this is the error:

Param quote { bar } failed assertion

That is, Quoted values are interpolated together with the surrounding quote { ... } but maybe that surrounding should be removed?

Mainly thinking about the original use case that triggered this:

assert(false, "Param $a_quote of type $a_type_quote is not supported as an argument")

As a side note, I'm also wondering if format strings wouldn't be useful to constructor identifiers. Something like this:

let hello = quote { hello };
let world = quote { world };
let name = f"{hello}_{world}";
let identifier: Quoted = name.as_identifier().unwrap(); 
println(identifier); // Prints "quote { hello_world }";

That way we wouldn't need to "glue" tokens because format strings kind of do that now. I'm also thinking about Elixir here, I guess in their macros you can operate with strings and eventually call String.to_atom to convert them to an atom that you can use to create a function, etc.

@jfecher
Copy link
Contributor

jfecher commented Sep 4, 2024

I like the thought of using format strings for name formatting as well, then re-converting them into Quoted values.

As far as the Param quote { bar } failed assertion issue goes that seems like a tough one. Even if we remove the quote { } portion, users wouldn't be able to control the amount of spaces between each token in the Quoted value.
If we just want to consider the name use case we can just ignore this I suppose and expect each Quoted value to only have a single token.

github-merge-queue bot pushed a commit that referenced this issue Sep 4, 2024
# Description

## Problem

Resolves #5899
Resolves #5914

## Summary

Two things here:
1. When interpolating quotes values inside a format string, we do that
without producing the `quote {` and `}` parts, which is likely what a
user would expect (similar to unquoting those values).
2. In order to create identifiers (or any piece of code in general) by
joining severa quoted values you can use format strings together with
the new `fmtstr::contents` method, which returns a `Quoted` value with
the string contents (that is, without the leading and trailing double
quotes).

## Additional Context

I originally thought about a method like `fmtstr::as_identifier` that
would try to parse the string contents as an identifier (maybe an
`Ident`, or maybe a `Path`), returning `Option<Quoted>` and `None` in
case it couldn't be parsed to that. But I think in general it could be
more useful to just get the string contents as a `Quoted` value. After
all, if it isn't an identifier you'll learn it later on once the value
is unquoted or interpolated.

## Documentation

Check one:
- [ ] No documentation needed.
- [x] Documentation included in this PR.
- [ ] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Done
Development

Successfully merging a pull request may close this issue.

2 participants