Skip to content

Commit 746d1bf

Browse files
committed
Allow to run a parser at compile time with new compiler
1 parent 31c60f6 commit 746d1bf

File tree

3 files changed

+204
-7
lines changed

3 files changed

+204
-7
lines changed

core/dparsergen/core/dynamictree.d

+178-7
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,152 @@ string treeToString(Location, alias LocationRangeImpl = LocationRangeStartLength
422422
return app.data;
423423
}
424424

425+
enum PossibleNonterminalTypes
426+
{
427+
none = 0,
428+
tree = 1,
429+
string = 2,
430+
array = 4,
431+
all = tree | string | array
432+
}
433+
434+
template NonterminalUnionImpl(alias CreatorInstance)
435+
{
436+
struct Union(PossibleNonterminalTypes possibleNonterminalTypes)
437+
{
438+
alias Location = CreatorInstance.Location;
439+
alias LocationRangeImpl = CreatorInstance.LocationRangeImpl;
440+
441+
template NonterminalType(SymbolID nonterminalID)
442+
if ((nonterminalID >= CreatorInstance.startNonterminalID
443+
&& nonterminalID < CreatorInstance.endNonterminalID)
444+
|| nonterminalID == SymbolID.max)
445+
{
446+
alias NonterminalType = CreatorInstance.NonterminalType!nonterminalID;
447+
}
448+
449+
union
450+
{
451+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.array)
452+
CreatorInstance.NonterminalArray valueArray;
453+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.string)
454+
string valueString;
455+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.tree)
456+
CreatorInstance.NonterminalTree valueTree;
457+
}
458+
459+
SymbolID nonterminalID = SymbolID.max;
460+
461+
inout(NonterminalType!nonterminalID2) get(SymbolID nonterminalID2)() inout
462+
in
463+
{
464+
assert(nonterminalID2 == nonterminalID, text(nonterminalID2, " ", nonterminalID));
465+
}
466+
do
467+
{
468+
static if (CreatorInstance.allNonterminals[nonterminalID2 - CreatorInstance.startNonterminalID].flags & NonterminalFlags.array)
469+
return valueArray;
470+
else static if (CreatorInstance.allNonterminals[nonterminalID2 - CreatorInstance.startNonterminalID].flags & NonterminalFlags.string)
471+
return valueString;
472+
else
473+
return valueTree;
474+
}
475+
476+
auto get(nonterminalID2s...)() inout if (nonterminalID2s.length >= 2)
477+
{
478+
foreach (nonterminalID2; nonterminalID2s)
479+
{
480+
if (nonterminalID2 == nonterminalID)
481+
return get!nonterminalID2();
482+
}
483+
assert(false);
484+
}
485+
486+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.tree)
487+
static Union create(SymbolID nonterminalID, CreatorInstance.NonterminalTree tree)
488+
in (CreatorInstance.isNonterminalTree(nonterminalID))
489+
{
490+
Union r;
491+
r.valueTree = tree;
492+
r.nonterminalID = nonterminalID;
493+
return r;
494+
}
495+
496+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.string)
497+
static Union create(SymbolID nonterminalID, string tree)
498+
in (CreatorInstance.isNonterminalString(nonterminalID))
499+
{
500+
Union r;
501+
r.valueString = tree;
502+
r.nonterminalID = nonterminalID;
503+
return r;
504+
}
505+
506+
static if (possibleNonterminalTypes & PossibleNonterminalTypes.array)
507+
static Union create(SymbolID nonterminalID, CreatorInstance.NonterminalArray tree)
508+
in (CreatorInstance.isNonterminalArray(nonterminalID))
509+
{
510+
Union r;
511+
r.valueArray = tree;
512+
r.nonterminalID = nonterminalID;
513+
return r;
514+
}
515+
516+
static Union create()(SymbolID nonterminalID)
517+
in (nonterminalID >= CreatorInstance.startNonterminalID && nonterminalID < CreatorInstance.endNonterminalID)
518+
{
519+
Union r;
520+
r.nonterminalID = nonterminalID;
521+
return r;
522+
}
523+
524+
void opAssign(PossibleNonterminalTypes possibleNonterminalTypes2)(
525+
Union!(possibleNonterminalTypes2) rhs)
526+
if (possibleNonterminalTypes2 != possibleNonterminalTypes)
527+
{
528+
static if ((possibleNonterminalTypes & PossibleNonterminalTypes.tree) && (possibleNonterminalTypes2 & PossibleNonterminalTypes.tree))
529+
if (CreatorInstance.isNonterminalTree(rhs.nonterminalID))
530+
{
531+
valueTree = rhs.valueTree;
532+
nonterminalID = rhs.nonterminalID;
533+
return;
534+
}
535+
static if ((possibleNonterminalTypes & PossibleNonterminalTypes.string) && (possibleNonterminalTypes2 & PossibleNonterminalTypes.string))
536+
if (CreatorInstance.isNonterminalString(rhs.nonterminalID))
537+
{
538+
valueString = rhs.valueString;
539+
nonterminalID = rhs.nonterminalID;
540+
return;
541+
}
542+
static if ((possibleNonterminalTypes & PossibleNonterminalTypes.array) && (possibleNonterminalTypes2 & PossibleNonterminalTypes.array))
543+
if (CreatorInstance.isNonterminalArray(rhs.nonterminalID))
544+
{
545+
valueArray = rhs.valueArray;
546+
nonterminalID = rhs.nonterminalID;
547+
return;
548+
}
549+
assert(0);
550+
}
551+
}
552+
553+
template Union(alias nonterminalIDs)
554+
{
555+
alias Union = Union!(() {
556+
PossibleNonterminalTypes possibleNonterminalTypes;
557+
static foreach (n; nonterminalIDs)
558+
{
559+
static if (CreatorInstance.allNonterminals[n - CreatorInstance.startNonterminalID].flags & NonterminalFlags.array)
560+
possibleNonterminalTypes |= PossibleNonterminalTypes.array;
561+
else static if (CreatorInstance.allNonterminals[n - CreatorInstance.startNonterminalID].flags & NonterminalFlags.string)
562+
possibleNonterminalTypes |= PossibleNonterminalTypes.string;
563+
else
564+
possibleNonterminalTypes |= PossibleNonterminalTypes.tree;
565+
}
566+
return possibleNonterminalTypes;
567+
}());
568+
}
569+
}
570+
425571
/**
426572
Class for creating trees during parsing.
427573
@@ -432,16 +578,19 @@ Params:
432578
stored (start + length, start + end, ...).
433579
*/
434580
class DynamicParseTreeCreator(alias GrammarModule, Location_,
435-
alias LocationRangeImpl = LocationRangeStartLength)
581+
alias LocationRangeImpl_ = LocationRangeStartLength)
436582
{
437583
alias Location = Location_;
584+
alias LocationRangeImpl = LocationRangeImpl_;
438585
alias LocationDiff = typeof(Location.init - Location.init);
439586
alias allTokens = GrammarModule.allTokens;
440587
alias allNonterminals = GrammarModule.allNonterminals;
441588
alias allProductions = GrammarModule.allProductions;
442589
alias Type = DynamicParseTree!(Location, LocationRangeImpl);
443590
alias NonterminalArray = DynamicParseTreeTmpArray!(Location,
444591
LocationRangeImpl);
592+
alias NonterminalTree = DynamicParseTree!(Location,
593+
LocationRangeImpl);
445594
enum startNonterminalID = GrammarModule.startNonterminalID;
446595
enum endNonterminalID = GrammarModule.endNonterminalID;
447596
enum startProductionID = GrammarModule.startProductionID;
@@ -454,16 +603,39 @@ class DynamicParseTreeCreator(alias GrammarModule, Location_,
454603
{
455604
static if (
456605
allNonterminals[nonterminalID - startNonterminalID].flags & NonterminalFlags.array)
457-
alias NonterminalType = DynamicParseTreeTmpArray!(Location,
458-
LocationRangeImpl);
606+
alias NonterminalType = NonterminalArray;
459607
else static if (
460608
allNonterminals[nonterminalID - startNonterminalID].flags & NonterminalFlags.string)
461609
alias NonterminalType = string;
462610
/*else static if (allNonterminals[nonterminalID - startNonterminalID].flags == NonterminalFlags.none
463611
|| allNonterminals[nonterminalID - startNonterminalID].flags == NonterminalFlags.empty)
464612
alias NonterminalType = typeof(null);*/
465613
else
466-
alias NonterminalType = DynamicParseTree!(Location, LocationRangeImpl);
614+
alias NonterminalType = NonterminalTree;
615+
}
616+
617+
static bool isNonterminalTree(SymbolID nonterminalID)
618+
{
619+
if (nonterminalID < startNonterminalID || nonterminalID >= endNonterminalID)
620+
return false;
621+
auto flags = allNonterminals[nonterminalID - startNonterminalID].flags;
622+
return (flags & (NonterminalFlags.array | NonterminalFlags.string)) == 0;
623+
}
624+
625+
static bool isNonterminalArray(SymbolID nonterminalID)
626+
{
627+
if (nonterminalID < startNonterminalID || nonterminalID >= endNonterminalID)
628+
return false;
629+
auto flags = allNonterminals[nonterminalID - startNonterminalID].flags;
630+
return (flags & NonterminalFlags.array) != 0;
631+
}
632+
633+
static bool isNonterminalString(SymbolID nonterminalID)
634+
{
635+
if (nonterminalID < startNonterminalID || nonterminalID >= endNonterminalID)
636+
return false;
637+
auto flags = allNonterminals[nonterminalID - startNonterminalID].flags;
638+
return (flags & (NonterminalFlags.array | NonterminalFlags.string)) == NonterminalFlags.string;
467639
}
468640

469641
/**
@@ -484,14 +656,13 @@ class DynamicParseTreeCreator(alias GrammarModule, Location_,
484656
the parser. The union can allow more nonterminals than necessary,
485657
which can reduce template bloat.
486658
*/
487-
alias NonterminalUnion = GenericNonterminalUnion!(DynamicParseTreeCreator).Union;
659+
alias NonterminalUnion = NonterminalUnionImpl!(DynamicParseTreeCreator).Union;
488660

489661
/**
490662
Tagged union of all possible nonterminals, which is used internally by
491663
the parser.
492664
*/
493-
alias NonterminalUnionAny = GenericNonterminalUnion!(DynamicParseTreeCreator).Union!(
494-
SymbolID.max, size_t.max);
665+
alias NonterminalUnionAny = NonterminalUnionImpl!(DynamicParseTreeCreator).Union!(PossibleNonterminalTypes.all);
495666

496667
/**
497668
Create a tree node for one production.

generator/dparsergen/generator/glrparsercodegen.d

+7
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,13 @@ const(char)[] createParserModule(LRGraph graph, string modulename,
12671267
Creator.NonterminalUnionAny nonterminal;
12681268
Token token;
12691269
}
1270+
1271+
// Workaround for https://issues.dlang.org/show_bug.cgi?id=24409
1272+
this(bool isToken, Location start = Location.init)
1273+
{
1274+
this.isToken = isToken;
1275+
this.start = start;
1276+
}
12701277
}
12711278
static struct StackEdge
12721279
{

tests/grammars/grammarexprs1_test.d

+19
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,22 @@ unittest
7676
Token(";", L.tokenID!"\";\"", 13, 14),
7777
]);
7878
}
79+
80+
// Running at CTFE requires a new compiler, because of https://issues.dlang.org/show_bug.cgi?id=24316
81+
static if (__VERSION__ >= 2108L || __traits(compiles, {
82+
import P = grammarexprs1;
83+
immutable grammarInfo = &P.grammarInfo;
84+
enum dummy = grammarInfo.allNonterminals.length;
85+
}))
86+
enum ctfeResult = () {
87+
import P = grammarexprs1;
88+
89+
alias L = grammarexprs1_lexer.Lexer!LocationBytes;
90+
alias test = testOnce!(P, L);
91+
92+
test("expr x*2+24*x*32", q{S(P(V("x"), Z("2")), "+", P(P(Z("24"), V("x")), Z("32")))});
93+
94+
return true;
95+
}();
96+
else
97+
pragma(msg, "Warning: Skipping CTFE test for old compiler");

0 commit comments

Comments
 (0)