Data structures are often defined with text diagrams. Like domain-specific languages, D can parse these strings and generate data structure definitions at compile time. We'll briefly demonstrate the technique by writing a parser for a simple diagram.
Let's execute the following steps to generate data structures from text diagrams:
pragma(msg)
or at runtime while debugging until the code looks right.mixin
expression to compile your code in a struct
block. If you use this pattern often, you may encapsulate it in a struct
block with a compile-time string parameter and then alias that parameter to a final name.This is shown in the following code:
enum diagramString = ' +------------------+ |LEN | ID | MSG | +------------------+ '; struct DiagramField { string name; int length; } DiagramField[] readDiagram(string diagram) { DiagramField[] fields; import std.string; auto lines = diagram.splitLines(); foreach(line; lines) { if(line.length == 0) continue; // blank line if(line[0] == '+') continue; // separator line auto parts = line.split("|"); foreach(part; parts) { if(part.length == 0) continue; DiagramField field; field.name = part.strip; field.length = part.length / 4; fields ~= field; } } return fields; } string toStructDefinition(DiagramField[] fields) { string code = "struct { "; foreach(field; fields) { string type; switch(field.length) { case 1: type = "ubyte"; break; case 2: type = "ushort"; break; case 4: type = "uint"; break; case 8: type = "ulong"; break; default: assert(0); } code ~= " " ~ type ~ " " ~ field.name ~ "; "; } code ~= " }"; return code; } struct StructFromDiagram(string diagram) { mixin(toStructDefinition(readDiagram(diagram))); } alias Message = StructFromDiagram!diagramString; /* // an alternative way to form to the struct struct Message { mixin(toStructDefinition(readDiagram(diagramString))); } */ void main() { import std.stdio; debug writeln(toStructDefinition(readDiagram(diagramString))); Message m; m.ID = 5; writeln(m); }
The output will be as follows:
StructFromDiagram!("x0a+------------------+x0a|LEN | ID | MSG |x0a+------------------+x0a")(0, 5, 0)
Since we used the alias
method, the internal type name (used in the automatic toString
implementation) is made from compile-time arguments, including the diagram. The alternate way results in a different name, but the same data.
Whereas we made data and code in the previous two recipes, here we finished our demonstration of the technique discussed in the previous recipes by creating a data structure from a string at compile time. The pattern is similar: parse the string and then output what it represents in D with the help of templates and mixins. We simply generate a struct
definition with appropriate data members. This definition can be mixed into an existing struct
type or aliased to a more convenient name and used directly. While parsing a diagram looks different, the code is basically the same as any other domain-specific language.
3.144.31.163