Skip to content

Instantly share code, notes, and snippets.

@marler8997
Created March 23, 2018 23:54
Show Gist options
  • Save marler8997/d693cf9196bce846ffa5a7bff80eaf2f to your computer and use it in GitHub Desktop.
Save marler8997/d693cf9196bce846ffa5a7bff80eaf2f to your computer and use it in GitHub Desktop.
void main()
{
int a = 42;
import std.stdio;
import std.conv : text;
//
// Want to create the string "a is 42"
//
writeln("Looking for 'a is 42':");
string attempt1 = text(mixin(interp("a is $(a)")));
writefln("attempt1 '%s'", attempt1); // NOPE
//assert(attempt1 == "a is 42"); // Fails
string attempt2 = text(interp("a is $(a)"));
writefln("attempt2 '%s'", attempt2); // NOPE
//assert(attempt2 == "a is 42"); // Fails
string attempt3 = text(mixin("a is $(a)".interp));
writefln("attempt3 '%s'", attempt3); // NOPE
//assert(attempt3 == "a is 42"); // Fails
}
//
//
// TODO: move what's below into std/experimental/typecons.d
//
//
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
// NEED TO PUBLICLY IMPORT THE `tuple` SYMBOL BECAUSE THE CODE GENERATED BY
// THE interpolate FUNCTION REQUIRES IT.
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
// !!!!!!!!!!!!!!!!!!!!!!!
public import std.typecons : tuple;
/**
Returns code meant to be used inside a "mixin" that creates a tuple.
*/
string interpolate(string str) pure @safe
{
return "tuple(" ~ interpolateHelper1(str) ~ ")";
}
/// ditto
alias interp = interpolate; // optional shorthand
private string interpolateHelper1(string str) pure @safe
{
import std.string : indexOf;
auto dollarIndex = str.indexOf("$");
if (dollarIndex < 0)
return `"` ~ str ~ `"`;
else if (dollarIndex == 0)
return interpolateHelper2(str[1 .. $]);
else
return `"` ~ str[0 .. dollarIndex] ~ `", ` ~ interpolateHelper2(str[dollarIndex + 1 .. $]);
}
// str starts with a dollar expression (just after the '$' character)
private string interpolateHelper2(string str) pure @safe
{
if (str[0] == '(')
{
uint depth = 1;
size_t i = 1;
for (;; i++)
{
if (i >= str.length)
throw new InterpolateException("unterminted $(...) expression");
if (str[i] == ')')
{
depth--;
if (depth == 0)
break;
}
else if (str[i] == '(')
{
depth++;
}
// TODO: handle parens inside comments/string literals, etc
// need a simple lexer that ignore comments/string literals
}
if (i == str.length - 1)
return str[1 .. i];
return str[1 .. i] ~ `,` ~ interpolateHelper1(str[i + 1 .. $]);
}
else if (str[0] == '$')
throw new InterpolateException("interpolate $$ not implemented");
else
throw new InterpolateException("interpolated expression $ currently requires parens $(...)");
}
class InterpolateException : Exception
{
this(string msg) pure @safe
{
super(msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment