Multiline raw strings can have placeholders with the common language expressions:
using sys{ log }
using string;
fn greet(name ?str, age int) {
log("{}\
Hello {name : "traveler"},
You look great for your {age} year{age != 1 ? "s"}!
")
}
greet("Mark", 49);
greet(?str, 1);
It prints:
Hello Mark,
You look great for your 49 years!
Hello traveler,
You look great for your 1 year!
As described here, the format expression of a multiline string defines extra indent, tab handling, line endings and extra linefeeds/indentaions.
There is more. It can contain one of three placeholder formats: "() {} []". If, for example, "{}" is presented, the string can contain generic Argentum expressions in curly braces, as in the above example. And the same for "[]" and "()" they just select the form of the placeholder syntax. If none is presented, the string contains no placeholders and act as a basic raw string.
String with placeholders is not a string literal. It is internally converted to more or like this code:
sys_StrBuilder
.putStr("Hello")
.putStr(name : "traveler") // see PS section
.putStr("{LF}You look great for your ")
.putInt(age)
.putStr(" year")
.putOptStr(age != 1 ? "s") // see PPS section
.putStr("{LF}")
.toStr();
In order for this code to work, class StrBuilder
from module sys
should have methods "put*" of types of the expressions in curly brackets.
Supported types and StringBuilder
method names:
Type | Method name |
int | putInt |
double | putDouble |
bool | putOptVoid |
function, lambda, delegate | not supported |
weak pointers | not supported, dereference it in {weak?_} |
all other pointers | putObj |
all pointers to strings | putStr |
optional types | putOpt* where * is name of the wrapped type. |
OptOptDouble
etc.Full multiline string format with placeholders is:
format =: prefix* tabs_handling placeholders? line_ends* extra_whitespaces*
prefix =: "." // emits space
| "t" // emits tab
tabs_handling =: [0-9]* // number of spaces to convert to a tab
placeholders =: "{}" | "()" | "[]"
line_ends =: "n" // adds "\n" to the end of line
| "r" // adds "\r"
extra_whitespaces =: "\" // adds `line_end` after the last line
| "\+" // adds `line_end` and a `prefix`
Example:
fn formatListItem(r Record) String { "t{}/
<li id={r.id}>
{escapeHtml(r.txt)}
</li>
"}
Placeholder expressions can span to multiple lines:
forRange(0, 3) `i {
log("{}\
Number {i} is {
i % 1 == 0
? "even"
: "odd"
}!
")
}
This prints:
Number 0 is even!
Number 1 is odd!
Number 2 is even!
Conclusion: Argentum string formatting is now in par with or even above the industry leading languages.
PS: Expression:
name : "traveller"
Reads as: use the value of the optional variable name
but if it's empty, use string "traveller".
Binary operator ":" plays the role of "else-operator" in other languages. Also in unwraps optional values.
PPS: Expression:
age != 1 ? "s"
Reads as: if age is not 1, return string "s" (otherwise return empty
).
Binary operator "?" plays the role of "if" operator in other languages. Also it creates optional values.
BTW StrBuilder
.putOptStr simply skips empty
values.
Does Argentum have a short syntax for single-line strings with placeholders [f-strings]?
I think it is useful, because single-line f-strings are needed much more often than multi-line f-strings.
Right now it doesn’t but it’s actually a very good idea, I’ll add it. What syntax do you suggest?
Done in v0.0.8: `single string with ${i} interpolations`