Skip to content

[articles/mixin.dd] Add concatenation, statements, types, expressions #3209

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 76 additions & 11 deletions articles/mixin.dd
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,96 @@ Ddoc

$(D_S String Mixins,

$(HEADERNAV_TOC)

$(P String Mixins (not to be confused with
$(DDLINK spec/template-mixin, Template Mixins, template mixins))
enable string constants to be compiled as regular D code
and inserted into the program.
Mixins can be used to generate:)

$(UL
$(LI Declarations)
$(LI Statements)
$(LI Types)
$(LI Expressions)
)
$(P
Combining this with compile time manipulation of strings
enables the creation of domain-specific languages.
For example, we can generate a declaration `struct Foo { int bar; }`
using string constants for the identifiers:
)

$(P For example, here we can create a template that generates
a struct with the named members:
)
---
enum name = "Foo";
enum m1 = "bar";
mixin("struct " ~ name ~
"{ int " ~ m1 ~ "; }");

enum f = Foo(2);
static assert(f.bar == 2);
---
$(P This can be encapsulated in an enum template:)
---
enum string genStruct(string name, string m1) =
"struct " ~ name ~ "{ int " ~ m1 ~ "; }";

mixin(genStruct!("Foo", "bar"));
---

$(H2 $(LNAME2 multiple-args, Concatenation of Multiple Arguments))

$(P `mixin()` can also concatenate multiple arguments, converting any
non-strings to strings:)
---
enum name = "Foo";
enum m1 = "bar";
$(CODE_HIGHLIGHT enum val = 4;)
mixin("struct ", name,
"{ int ", m1, " = ", $(CODE_HIGHLIGHT val), "; }");

enum f = Foo();
static assert(f.bar == 4);
---
template GenStruct(string Name, string M1)
{
const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}

mixin(GenStruct!("Foo", "bar"));
$(H2 $(LNAME2 declarations, Generating Declarations))

---
enum s = "int y;";
mixin(s);
y = 4; // ok, mixin declared y
---

$(H2 $(LNAME2 statements, Generating Statements))

---
int x = 3;
mixin("
foreach (i; 0 .. 3)
writeln(x + i);
");
---
$(P See also: $(GLINK2 statement, MixinStatement).)

$(H2 $(LNAME2 types, Generating Types))

---
$(P which generates:)
mixin("int")* p; // int* p
mixin("int")[] a; // int[] a;
mixin("int[]") b; // int[] b;
---
struct Foo { int bar; }

$(H2 $(LNAME2 expressions, Generating Expressions))

---
int foo(int x)
{
return mixin("x +", 1) * 7; // same as `return (x + 1) * 7`
}
---

$(H2 $(LNAME2 cpp, Comparison with C preprocessor))

$(P Superficially, since D mixins can manipulate text and compile
the result, it has some similar properties to the C preprocessor.
Expand Down Expand Up @@ -61,7 +126,7 @@ END

This monkey business is impossible with mixins.
Mixed in text must form complete declarations,
statements, or expressions.
statements, types, or expressions.
)

$(LI C macros will affect everything following that has
Expand Down
7 changes: 7 additions & 0 deletions spec/module.dd
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,13 @@ $(GNAME MixinDeclaration):
$(GLINK DeclDefs), and is compiled as such.
)

$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
enum s = "int y;";
mixin(s);
y = 4; // ok, mixin declared y
---
)

$(H2 $(LEGACY_LNAME2 PackageModule, package-module, Package Module))

Expand Down
26 changes: 11 additions & 15 deletions spec/statement.dd
Original file line number Diff line number Diff line change
Expand Up @@ -1999,30 +1999,26 @@ $(GNAME MixinStatement):
)

$(SPEC_RUNNABLE_EXAMPLE_RUN
---
import std.stdio;

void main()
{
int i = 0;
---
int x = 3;
mixin("
int x = 3;
for (; i < 3; i++)
writeln(x + i, i);
foreach (i; 0 .. 3)
writeln(x + i);
"); // ok
---
)

enum s = "int y;";
mixin(s); // ok
y = 4; // ok, mixin declared y
$(SPEC_RUNNABLE_EXAMPLE_COMPILE
---
int y;

string t = "y = 3;";
//mixin(t); // error, t is not evaluatable at compile time
//mixin("y =") 4; // error, string must be complete statement

//mixin("y =") 4; // error, string must be complete statement
mixin("y =" ~ "4;"); // ok
mixin("y =", 2+2, ";"); // ok
}
---
---
)

$(SPEC_SUBNAV_PREV_NEXT expression, Expressions, arrays, Arrays)
Expand Down