보간 표현식 시퀀스

보간 표현식 시퀀스 (Interpolation Expression Sequence)

문자열 리터럴 데이터와 값을 섞어 쓸 수 있는 D의 보간 표현식 시퀀스(IES, Interpolation Expression Sequence)를 다루는 페이지입니다. IES 리터럴의 종류, 표현식이 어떻게 변환되는지, 그리고 이를 받아 처리하는 방법까지 정리했어요.

출처: Interpolation Expression Sequence — D Language Specification

본문

보간 표현식 시퀀스(IES, Interpolation Expression Sequence)는 문자열 리터럴 데이터와 값을 교차 배치하는 표현식입니다. 보간 표현식은 문자열처럼 쓰이지만, 이를 받을 수 있는 함수에 직접 전달되는 값을 담을 수 있어요. 이는 오버로드되거나 템플릿 함수로 처리될 수 있는 표현식의 시퀀스로 변환됩니다.

IES 리터럴 (IES Literals)

InterpolationExpressionSequence:
 InterpolatedDoubleQuotedLiteral
 InterpolatedWysiwygLiteral
 InterpolatedTokenLiteral

보간 표현식 시퀀스는 wysiwyg 따옴표, 이중 따옴표, 또는 토큰 리터럴 중 하나일 수 있습니다. 이스케이프(escape)가 들어갈 수 있는 것은 이중 따옴표 리터럴뿐입니다.

문자열 리터럴과 달리, IES 리터럴은 문자열 표현식의 문자 타입 너비를 정의하는 접미사를 가질 수 없습니다.

이중 따옴표 IES 리터럴 (Double Quoted IES Literals)

InterpolatedDoubleQuotedLiteral:
 i" InterpolatedDoubleQuotedCharactersopt "

InterpolatedDoubleQuotedCharacters:
 InterpolatedDoubleQuotedCharacter
 InterpolatedDoubleQuotedCharacter InterpolatedDoubleQuotedCharacters

InterpolatedDoubleQuotedCharacter:
 DoubleQuotedCharacter
 InterpolationEscapeSequence
 InterpolationExpression

InterpolationEscapeSequence:
 EscapeSequence
 \$

InterpolationExpression:
 $( AssignExpression )

DoubleQuotedString처럼, 이중 따옴표 IES 리터럴은 이스케이프 문자를 가질 수 있습니다. 일반적인 이스케이프에 더해 리터럴 $를 이스케이프할 수 있는 능력이 추가되었어요.

$ 뒤에 왼쪽 괄호가 아닌 어떤 문자가 오면, 그 $는 표현식 안에서 리터럴 $로 취급됩니다. 즉 이스케이프할 필요가 없습니다.

InterpolationExpression 안의 표현식은 완전한 D 표현식이며, 그 부분 안에서는 이스케이프가 필요 없습니다.

Wysiwyg IES 리터럴 (Wysiwyg IES Literals)

InterpolatedWysiwygLiteral:
 i` InterpolatedWysiwygCharactersopt `

InterpolatedWysiwygCharacters:
 InterpolatedWysiwygCharacter
 InterpolatedWysiwygCharacter InterpolatedWysiwygCharacters

InterpolatedWysiwygCharacter:
 WysiwygCharacter
 InterpolationExpression

Wysiwyg("보이는 그대로", what you see is what you get) IES 리터럴은 WysiwygString 문자열처럼 정의되지만, 백쿼트(backquote) 문법만 지원합니다. 이 리터럴 안에서는 어떤 이스케이프도 인식되지 않습니다.

토큰 IES 리터럴 (Token IES Literals)

InterpolatedTokenLiteral:
 iq{ InterpolatedTokenStringTokensopt }

InterpolatedTokenStringTokens:
 InterpolatedTokenStringToken
 InterpolatedTokenStringToken InterpolatedTokenStringTokens

InterpolatedTokenStringToken:
 InterpolatedTokenNoBraces
 { InterpolatedTokenStringTokensopt }

InterpolatedTokenNoBraces:
 TokenNoBraces
 InterpolationExpression

TokenString처럼, IES 토큰 리터럴은 InterpolationExpression을 제외하고 유효한 D 토큰만을 포함해야 합니다. 이스케이프는 인식되지 않습니다.

표현식 변환 (Expression Translation)

렉서(lexer)가 보간 표현식 시퀀스를 만나면, 토큰은 표현식의 시퀀스로 변환되어 단일 토큰을 대체합니다. 시퀀스는 항상 표현식 core.interpolation.InterpolationHeader()로 시작하고 core.interpolation.InterpolationFooter()로 끝납니다.

토큰에서 리터럴 문자열 데이터인 각 부분 str은 표현식 core.interpolation.InterpolatedLiteral!(str)로 변환됩니다.

토큰에서 InterpolationExpression인 각 부분 $(expr)은 시퀀스 core.interpolation.InterpolatedExpression!(expr), expr로 변환됩니다.

// simple version of std.typecons.Tuple
struct Tuple(T...) { T value; }
Tuple!T tuple(T...)(T value) { return Tuple!T(value); }

import core.interpolation;
string name = "John Doe";
auto items = tuple(i"Hello, $(name), how are you?");
assert(items == tuple(
 InterpolationHeader(), // denotes the start of an IES
 InterpolatedLiteral!("Hello, ")(), // literal string data
 InterpolatedExpression!("name")(), // expression literal data
 name, // expression passed directly
 InterpolatedLiteral!(", how are you?")(), // literal string data
 InterpolationFooter())); // denotes the end of an IES

core.interpolation 타입

core.interpolation에 정의된 타입은 IES를 사용하기 위해 import 할 필요가 없습니다. IES가 사용될 때 자동으로 import 되요. 이 타입들은 컴파일 타임에 처리를 위해 IES를 쉽게 내부 조사(introspect)할 수 있도록 정의되어 있습니다.

InterpolationHeader와 InterpolationFooter

InterpolationHeaderInterpolationFooter 타입은 IES를 처리하는 함수를 쉽게 오버로드할 수 있게 하는 빈 구조체입니다. 이들은 표현식 목록의 어떤 부분이 IES를 통해 전달되었는지 이해하는 데도 사용할 수 있습니다.

이 타입들은 빈 문자열을 반환하는 toString 정의를 가집니다. 그래서 IES를 텍스트로 변환하려는 함수(예: std.stdio.writeln이나 std.conv.text)가 처리할 수 있습니다.

InterpolatedLiteral

InterpolatedLiteral 타입은 IES의 문자열 리터럴 부분에 컴파일 타임 접근을 제공하는 빈 구조체입니다. 이 타입은 또한 이 값이 대체한 시퀀스의 부분을 반환하는 toString 멤버 함수를 제공합니다.

InterpolatedExpression

InterpolatedExpression 타입은 다음 표현식을 형성하는 데 쓰인 리터럴에 컴파일 타임 접근을 제공하는 빈 구조체입니다. 빈 문자열을 반환하는 toString 멤버 함수가 있습니다. 또한 타입을 구성하는 데 쓰인 템플릿 매개변수와 같은 값을 가지는 enum expression 멤버가 있어요.

string name = "John Doe";
auto ies = i"Hello, $(name)";
static assert(is(typeof(ies[0]) == InterpolationHeader));
static assert(ies[1].toString() == "Hello, ");
static assert(ies[2].expression == "name");
assert(ies[3] == name);
static assert(is(typeof(ies[4]) == InterpolationFooter));

IES 수용과 처리 (Accepting and Processing IES)

IES를 수용하는 권장 메커니즘은, 명시적인 InterpolationHeaderInterpolationFooter 매개변수로 둘러싸인 시퀀스 안의 다양한 매개변수와 일치하는 가변 템플릿(variadic template) 함수를 제공하는 것입니다.

void processIES(Sequence...)(InterpolationHeader, Sequence data, InterpolationFooter)
{
 // process `data` here
}

IES는 보간 표현식으로 타입을 담을 수도 있습니다. 이것은 가변 템플릿 매개변수에 전달해 사용할 수 있어요.

template processIESAtCompileTime(InterpolationHeader header, Sequence...)
{
 static assert(Sequence[$-1] == InterpolationFooter());
}

alias result = processIES!i"Here is a type: $(int)";

문자열로 변환 (Converting to a String)

많은 경우 IES를 문자열로 변환하는 것이 바람직합니다. Phobos 함수 std.conv.text는 IES를 문자열로 변환해, 문자열 변수에 할당하거나 문자열을 받는 함수를 호출하는 등 문자열이 필요한 어떤 문맥에서도 사용할 수 있게 해 줍니다.

import std.conv : text;
string name = "John Doe";

string badgreeting = i"Hello, $(name)"; // Error
string greeting = i"Hello, $(name)".text; // OK
assert(greeting == "Hello, John Doe");

IES를 받기를 원하는 라이브러리 작성자는 std.conv에 의존하기보다는 IES를 수용하는 오버로드를 제공하는 것이 매우 권장됩니다. std.conv는 불필요한 할당을 유발하기 때문이에요. 특히 악의적인 사용자 제공 데이터로 특정 유형의 주입 공격이 가능한 경우에 중요합니다.

더 알아보기

  • Lexical — 렉서가 토큰을 어떻게 다루는지.
  • Grammar — D 문법 전체 정의.