DCD/constants-gen/generator.d

224 lines
5.1 KiB
D
Executable File

#!/usr/bin/env rdmd
import std.algorithm;
import std.ascii;
import std.file;
import std.regex;
import std.stdio;
import std.string;
struct ConstantCompletion
{
string[] identifiers;
string ddoc;
}
struct SingleConstantCompletion
{
string identifier;
string ddoc;
string toString() const
{
return "ConstantCompletion(\"" ~ identifier ~ "\", `" ~ ddoc.replaceAll(ctRegex!"`+",
"` ~ \"$0\" ~ `") ~ "`)";
}
}
unittest
{
ConstantCompletion completion;
completion.ddoc = "'abc``def'";
assert(completion.toString == q{ConstantCompletion("", `'abc` ~ "``" ~ `def'`)});
}
ConstantCompletion[] parsePragmas(string ddoc)
{
ConstantCompletion[] completions;
bool foundTerminator;
ConstantCompletion current;
bool inInlineCode;
bool seekingToFirst = true;
string indent;
void addCurrent()
{
if (seekingToFirst)
{
current = ConstantCompletion.init;
return;
}
// ret still has `$(DD content)` around it, strip that
if (current.ddoc.startsWith("$(DD"))
{
current.ddoc = current.ddoc["$(DD".length .. $].strip;
if (current.ddoc.endsWith(")"))
current.ddoc = current.ddoc[0 .. $ - 1].stripRight;
}
completions ~= current;
current = ConstantCompletion.init;
}
foreach (line; ddoc.lineSplitter!(KeepTerminator.yes))
{
auto strippedLine = line.stripLeft;
if (strippedLine.startsWith("$(SPEC_SUBNAV_PREV_NEXT"))
{
addCurrent();
// end of macros
foundTerminator = true;
break;
}
else if (strippedLine.startsWith("$(DT $(LNAME2 "))
{
addCurrent();
seekingToFirst = false;
indent = line[0 .. $ - strippedLine.length];
string identifierLine = strippedLine.stripRight; // fully stripped
auto closing = identifierLine.indexOfAny("),");
if (closing == -1)
closing = identifierLine.length;
current.identifiers = [identifierLine["$(DT $(LNAME2".length .. closing].strip];
}
else if (!seekingToFirst)
{
if (line.startsWith("---")) // code blocks aren't indented
inInlineCode = !inInlineCode;
if (inInlineCode)
current.ddoc ~= line;
else
{
if (line.startsWith(indent)) // strip indentation equal to DT (section header)
current.ddoc ~= line[indent.length .. $];
else
current.ddoc ~= line;
}
}
}
if (!foundTerminator)
throw new Exception("Could not find '$(SPEC_SUBNAV_PREV_NEXT' line in pragma.dd, format of the file has changed and code needs to be adjusted.");
return completions;
}
ConstantCompletion[] parseTraits(string ddoc)
{
ConstantCompletion[] completions;
bool foundTerminator;
ConstantCompletion current;
bool inInlineCode;
bool seekingToFirst = true;
string indent;
void addCurrent()
{
current.ddoc = current.ddoc.strip;
if (seekingToFirst || current == ConstantCompletion.init)
{
current = ConstantCompletion.init;
return;
}
completions ~= current;
current = ConstantCompletion.init;
}
foreach (line; ddoc.lineSplitter!(KeepTerminator.yes))
{
if (line.stripLeft.startsWith("$(SPEC_SUBNAV_PREV_NEXT"))
{
addCurrent();
foundTerminator = true;
break;
}
else if (line.canFind("$(GNAME "))
{
addCurrent();
ptrdiff_t i = line.indexOf("$(GNAME ");
while (i != -1)
{
auto closing = line.indexOfAny("),", i);
current.identifiers ~= line[i + "$(GNAME ".length .. closing].strip;
i = line.indexOf("$(GNAME ", closing);
}
seekingToFirst = false;
if (current.identifiers.length == 1 && current.identifiers[0][0].isUpper)
seekingToFirst = true; // not considering capitalized identifiers traits (TraitsKeyword, TraitsExpression, etc.)
}
else if (!seekingToFirst)
{
if (line.startsWith("---"))
inInlineCode = !inInlineCode;
if (inInlineCode)
current.ddoc ~= line;
else
{
if (!current.ddoc.length)
indent = line[0 .. $ - line.stripLeft.length];
if (line.startsWith(indent))
current.ddoc ~= line[indent.length .. $];
else
current.ddoc ~= line;
}
}
}
if (!foundTerminator)
throw new Exception("Could not find '$(SPEC_SUBNAV_PREV_NEXT' line in traits.dd, format of the file has changed and code needs to be adjusted.");
return completions;
}
void main()
{
immutable pragmaDDoc = readText("pragma.dd");
immutable traitsDDoc = readText("traits.dd");
auto pragmas = parsePragmas(pragmaDDoc);
auto traits = parseTraits(traitsDDoc);
string part1 = `//
//
// this file is auto generated by constants-gen/generator.d, do not edit manually.
//
//
module dcd.common.constants2;
import dcd.common.constants : ConstantCompletion;
/**
* Pragma arguments
*/
immutable ConstantCompletion[] pragmas = [
// generated from pragma.dd`;
string part2 = `];
/**
* Traits arguments
*/
immutable ConstantCompletion[] traits = [
// generated from traits.dd`;
string part3 = "];";
auto file = File("../src/dcd/common/constants2.d", "w");
file.writeln(part1);
foreach (pragma_; pragmas.sorted)
file.writeln('\t', pragma_, ",");
file.writeln(part2);
foreach (trait; traits.sorted)
file.writeln('\t', trait, ",");
file.writeln(part3);
}
auto sorted(T)(T range)
{
return range.map!(a => a.identifiers.map!(identifier => SingleConstantCompletion(identifier,
a.ddoc))).join.sort!"a.identifier < b.identifier";
}