Skip to content

Commit

Permalink
Update after Community Review Round 1 (#184)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright authored and atilaneves committed Dec 16, 2019
1 parent 148001a commit 1f5959a
Showing 1 changed file with 79 additions and 26 deletions.
105 changes: 79 additions & 26 deletions DIPs/DIP1027.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,12 @@ easier to review for correctness.
For many such examples, see [String Interpolation](https://en.wikipedia.org/wiki/String_interpolation).
* Jason Helson submitted a DIP [String Syntax for Compile-Time Sequences](https://github.com/dlang/DIPs/pull/140).
* [Adam Ruppe's string interpolation proposal](http://dpldocs.info/this-week-in-d/Blog.Posted_2019_05_13.html)
* [Jonathan Marler's Interpolated Strings](http://github.com/dlang/dmd/pull/7988)

## Description

```
writefln(i"I ate %apples and %{d}bananas totalling %(apples + bananas) fruit.");
writefln(i"I ate $apples and ${%d}bananas totalling $(apples + bananas) fruit.");
```
gets rewritten as:
```
Expand All @@ -51,26 +52,43 @@ writefln("I ate %s and %d totalling %s fruit.", apples, bananas, apples + banana
This will also work with `printf`:

```
printf(i"I ate %{d}apples and %{d}bananas totalling %{d}(apples + bananas) fruit.\n");
printf(i"I ate ${%d}apples and ${%d}bananas totalling ${%d}(apples + bananas) fruit.\n");
```
becomes:
```
printf("I ate %s and %d totalling %s fruit.\n", apples, bananas, apples + bananas);
printf("I ate %d and %d totalling %d fruit.\n", apples, bananas, apples + bananas);
```

The `{d}` syntax is for circumstances when the format specifier needs to be anything other that `s`,
The `{%d}` syntax is for circumstances when the format specifier needs to be anything other than `%s`,
which is the default. What goes between the `{` `}` is not specified, so this capability
can work with future format specification improvements without needing to update
the core language. It also makes interpolated strings agnostic about what the format
specifications are, as long as they start with `%`.
specifications are.


The interpolated string starts as a special string, `InterpolatedString`, which is the same as a
`DoubleQuotedString` but with an `i` prefix and no `StringPostFix`. This appears in the grammar
The interpolated string starts as a special string token, `InterpolatedString`, which is the same as a
`DoubleQuotedString` but with an `i` prefix and no `StringPostFix`.

```
InterpolatedString:
i" DoubleQuotedCharacters "
```

The `InterpolatedString` appears in the parser grammar
as an `InterpolatedExpression`, which is under `PrimaryExpression`.

```
InterpolatedExpression:
InterpolatedString
InterpolatedString StringLiterals
StringLiterals:
StringLiteral
StringLiteral StringLiterals
```

`InterpolatedExpresssion`s undergo semantic analysis similar to `MixinExpression`.
The string is scanned from left to right according to the following grammar:
The contents of the `InterpolatedExpression` must conform to the following grammar:

```
Elements:
Expand All @@ -79,9 +97,9 @@ Elements:
Element:
Character
'%%'
'%' Argument
'%' FormatString Argument
'$$'
'$' Argument
'$' FormatString Argument
FormatString:
'{' FormatString '}'
Expand Down Expand Up @@ -111,40 +129,72 @@ CharacterNoParen:
characters excluding '(' and ')'
```

The `InterpolatedExpression` is converted to a tuple expression, where the first element
is the transformed string literal and the `Argument`s form the remainder of the elements.
The `InterpolatedExpression` is converted to a tuple expression, where the first tuple element
is the transformed string literal and the `Argument`s form the remainder of the tuple elements.

The transformed string literal is constructed as follows:

If the `Element` is:

* `Character`, it is written to the output string.
* `'%%'`, a '%' is written to the output string.
* `'%' Argument`, then '%s' is written to the output string.
* `'%' '{' FormatString '}' Argument`, then '%' `FormatString` is written to the output string.
* `'$$'`, a '$' is written to the output string.
* `'$' Argument`, then '%s' is written to the output string.
* `'$' '{' FormatString '}' Argument`, then '$' `FormatString` is written to the output string.

The string becomes the first element of the tuple.

If the `Argument` is an `Identifier`, it is inserted in the tuple as an `IdentifierExpression`.
If the `Argument` is an `Identifier`, it is appended to the tuple as an `IdentifierExpression`.
If the `Argument` is an `Expression`, it is lexed and parsed (including the surrounding parentheses)
like `MixinExpressions` and inserted into the tuple as an `Expression`.
like `MixinExpressions` and appended to the tuple as an `Expression`.

Compile-time errors will be generated if the `Elements` do not fit the grammar.

### Concatenations

In order to facilitate convenient formatting of long strings, if a `StringLiteral` follows an `InterpolatedString`,
it is appended to the `InterpolatedString` in the parsing pass. (Not the lexer pass.)
A `StringPostfix` may not appear on any of them.
Such concatenations enable the various string literal types to be used as `InterpolatedStrings`,
such as:

```
i""q{apples and $("bananas")}
```
yielding a tuple expression:
```
"apples and %s", "bananas"
```

### Limitations

#### Mixing Conventional Format Arguments With Interpolated Strings

Interpolated string formats cannot be mixed with conventional elements:

```
writefln(i"making %bread using %d ingredients", 6); // error, %d is not a valid element
string tool = "hammer";
writefln(i"hammering %s with $tool", "nails");
```
will produce:
```
string tool = "hammer";
writefln("hammering %s with %s", tool, "nails");
```
as the interpolated arguments will always come first, and out of order with the conventional
arguments. This error is not detected.

#### Format Specification Errors

No attempt is made to diagnose format specification errors, such as attempting to format
an integer as a floating point value. The meaning of the format specifications is unknown
to the core language.

Interpolated strings will not accept `*` format specifications that require extra arguments.
Such will produce a runtime error with `writefln` and undefined behavior with
`printf`, because the arguments won't line up with the formats. The compiler does not check
the formats for validity.

No attempt is made to check that the format specification is compatible with the argument type.
Making such checks would require that detailed knowledge of `printf` and `writef` be hardwired
into the core language, as well as knowledge of which formatting function is being called.
#### W and D Interpolated Strings

`wchar` and `dchar` interpolated strings are not allowed. These can be added
later if necessary, but the use of such literals
has turned out to be rare. They can always be formed with a cast if desired.


## Breaking Changes and Deprecations
Expand All @@ -153,6 +203,9 @@ Since the interpolated string is a new token, no existing code is broken.

## Reference

* [DIP 1027---String Interpolation---Community Review Round 1]
(https://digitalmars.com/d/archives/digitalmars/D/DIP_1027---String_Interpolation---Community_Review_Round_1_333503.html)

## Copyright & License
Copyright (c) 2019 by the D Language Foundation

Expand Down

0 comments on commit 1f5959a

Please sign in to comment.