Skip to content

Commit

Permalink
Update release
Browse files Browse the repository at this point in the history
  • Loading branch information
vczh committed Jul 30, 2023
1 parent b055346 commit 562d572
Show file tree
Hide file tree
Showing 10 changed files with 1,911 additions and 616 deletions.
1 change: 1 addition & 0 deletions Import/GacUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4254,6 +4254,7 @@ Event Receiver
,lostFocus(_sender)
,caretNotify(_sender)
,clipboardNotify(_sender)
,renderTargetChanged(_sender)
{
}

Expand Down
233 changes: 229 additions & 4 deletions Import/VlppGlrParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2632,7 +2632,13 @@ Input

// if competitions happen between new surviving traces
// remove traces that known to have lost the competition
CheckBackupTracesBeforeSwapping(currentTokenIndex);
if (CheckBackupTracesBeforeSwapping(currentTokenIndex))
{
// after competition are closed
// different surviving traces might be mergable
// merge them and remove unnecessary traces
TryMergeSurvivingTraces();
}

EndSwap();

Expand Down Expand Up @@ -2806,6 +2812,7 @@ namespace vl
{
namespace automaton
{
using namespace collections;

/***********************************************************************
EnsureTraceWithValidStates
Expand All @@ -2831,7 +2838,7 @@ AreTwoEndingInputTraceEqual
{
// two traces equal to each other if
// 1) they are in the same state
// 2) they have the same executedReturnStack (and therefore the same returnStack)
// 2) they have the same executedReturnStack and returnStack
// 3) they are attending same competitions
// 4) they have the same switchValues
// 5) the candidate has an ending input
Expand All @@ -2850,7 +2857,7 @@ AreTwoEndingInputTraceEqual
MergeTwoEndingInputTrace
***********************************************************************/

void TraceManager::MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate)
Trace* TraceManager::MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate)
{
// goal of this function is to create a structure
// NEWTRACE ---+->AMBIGUITY
Expand All @@ -2861,9 +2868,14 @@ MergeTwoEndingInputTrace
// a former trace will copy CANDIDATE and insert before CANDIDATE
// and CANDIDATE will be initialized to an empty trace

// if a former trace is created to replace the candidate
// in which case the candidate becomes a merge trace
// the former trace is returned

if (candidate->state == -1)
{
AddTraceToCollection(candidate, newTrace, &Trace::predecessors);
return nullptr;
}
else
{
Expand All @@ -2879,7 +2891,210 @@ MergeTwoEndingInputTrace

AddTraceToCollection(candidate, formerTrace, &Trace::predecessors);
AddTraceToCollection(candidate, newTrace, &Trace::predecessors);
return formerTrace;
}
}

/***********************************************************************
TryMergeSurvivingTraces
***********************************************************************/

void TraceManager::TryMergeSurvivingTraces()
{
#define ERROR_MESSAGE_PREFIX L"vl::glr::automaton::TraceManager::TryMergeSurvivingTraces()#"
if (concurrentCount == 0) return;

struct EndingOrMergeTraceData
{
bool surviving = true; // becomes false when this trace does not survive anymore
};

vint32_t removedTracesCount = 0;
Dictionary<Trace*, EndingOrMergeTraceData> endingOrMergeTraces;
Group<vint32_t, Trace*> endingOrMergeTracesByState;

// index surviving traces
for (vint32_t i = 0; i < concurrentCount; i++)
{
auto trace = backupTraces->Get(i);
endingOrMergeTraces.Add(trace, {});

if (trace->state == -1)
{
endingOrMergeTracesByState.Add(EnsureTraceWithValidStates(trace)->state, trace);
}
else if (trace->byInput == Executable::EndingInput)
{
endingOrMergeTracesByState.Add(trace->state, trace);
}
}

#if defined VCZH_MSVC && defined _DEBUG
// check assumptions
for (vint32_t i = 0; i < concurrentCount; i++)
{
auto trace = backupTraces->Get(i);
if (trace->state == -1)
{
auto predecessorId = trace->predecessors.first;
while (predecessorId != nullref)
{
auto predecessor = GetTrace(predecessorId);
predecessorId = predecessor->predecessors.siblingNext;

CHECK_ERROR(endingOrMergeTraces.Keys().IndexOf(predecessor) == -1, ERROR_MESSAGE_PREFIX L"Internal error: Predecessors of a merge trace should not survive.");
}
}
else if (trace->byInput == Executable::EndingInput)
{
CHECK_ERROR(trace->predecessors.first == trace->predecessors.last, ERROR_MESSAGE_PREFIX L"Internal error: Executable::EndingInput trace could not have multiple predecessors.");
}
}
#endif

// unsurvive a trace
auto unsurviveTrace = [&](Trace* trace, EndingOrMergeTraceData& data)
{
if (data.surviving)
{
data.surviving = false;
removedTracesCount++;
}
};

// check if a trace survived
// if an Executable::EndingInput trace survived but its only predecessor does not
// it becomes not survived
auto ensureEndingTraceSurvived = [&](Trace* trace)
{
if (trace == initialTrace) return true;

auto& data = const_cast<EndingOrMergeTraceData&>(endingOrMergeTraces[trace]);
if (!data.surviving) return false;

if (trace->state != -1)
{
auto predecessorId = trace->predecessors.first;
if (predecessorId != nullref)
{
auto predecessor = GetTrace(predecessorId);
if (!endingOrMergeTraces[predecessor].surviving)
{
unsurviveTrace(trace, data);
}
}
}
return data.surviving;
};

// find surviving traces that merge
for (vint32_t i = 0; i < concurrentCount; i++)
{
// get the next surviving Executable::EndingInput trace
auto trace = backupTraces->Get(i);
if (trace->state != -1 && trace->byInput != Executable::EndingInput) continue;
if (!ensureEndingTraceSurvived(trace)) continue;
auto realTrace = EnsureTraceWithValidStates(trace);

// find all traces Executable::EndingInput traces with the same state that after it
auto&& candidates = endingOrMergeTracesByState[realTrace->state];
vint index = candidates.IndexOf(trace);
for (vint j = index + 1; j < candidates.Count(); j++)
{
// ensure the candidate also survived
auto candidate = candidates[j];
if (!ensureEndingTraceSurvived(candidate)) continue;
auto realCandidate = EnsureTraceWithValidStates(candidate);

if (AreTwoEndingInputTraceEqual(realTrace, realCandidate))
{
// merge two traces
if (trace == realTrace)
{
// if trace is an ordinary trace
if (candidate == realCandidate)
{
// if candidate is an ordinary trace
// turn trace into a merge trace
auto formerTrace = MergeTwoEndingInputTrace(candidate, trace);
CHECK_ERROR(formerTrace != nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should not be null.");
realTrace = formerTrace;
}
else
{
// if candidate is a merge trace
// turn trace into a merge trace
// give the rest of predecessors of candidate to trace
auto candidateHead = GetTrace(candidate->predecessors.first);
auto candidateNextId = candidateHead->predecessors.siblingNext;

candidateHead->predecessors.siblingNext = nullref;
auto formerTrace = MergeTwoEndingInputTrace(candidateHead, trace);
CHECK_ERROR(formerTrace != nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should not be null.");
realTrace = formerTrace;

candidateHead->predecessors.siblingNext = candidateNextId;
trace->predecessors.last = candidate->predecessors.last;
candidate->predecessors.first = nullref;
candidate->predecessors.last = nullref;
}
}
else
{
// if trace is a merge trace
if (candidate == realCandidate)
{
// if candidate is an ordinary trace
// merge candidate into trace
auto formerTrace = MergeTwoEndingInputTrace(candidate, trace);
CHECK_ERROR(formerTrace == nullptr, ERROR_MESSAGE_PREFIX L"Internal error: formerTrace should be null.");
}
else
{
// if candidate is an ordinary trace
// give all predecessors of candidate to trace
auto traceTail = GetTrace(trace->predecessors.last);
auto candidateHead = GetTrace(candidate->predecessors.first);

traceTail->predecessors.siblingNext = candidateHead;
candidateHead->predecessors.siblingPrev = traceTail;

trace->predecessors.last = candidate->predecessors.last;
candidate->predecessors.first = nullref;
candidate->predecessors.last = nullref;
}
}

auto& data = const_cast<EndingOrMergeTraceData&>(endingOrMergeTraces[candidate]);
unsurviveTrace(candidate, data);
}
}
}

if (removedTracesCount > 0)
{
// mark all unsurviving traces
for (vint32_t i = 0; i < concurrentCount; i++)
{
auto trace = backupTraces->Get(i);
vint index = endingOrMergeTraces.Keys().IndexOf(trace);
if (index == -1) continue;
if (endingOrMergeTraces.Values()[index].surviving) continue;
backupTraces->Set(i, nullptr);
}

// clean up surviving trace list
vint writing = 0;
for (vint32_t i = 0; i < concurrentCount; i++)
{
auto trace = backupTraces->Get(i);
if (!trace) continue;
backupTraces->Set(writing++, trace);
}
concurrentCount -= removedTracesCount;
}

#undef ERROR_MESSAGE_PREFIX
}
}
}
Expand Down Expand Up @@ -3080,8 +3295,9 @@ CheckAttendingCompetitionsOnEndingEdge
CheckBackupTracesBeforeSwapping
***********************************************************************/

void TraceManager::CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex)
bool TraceManager::CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex)
{
bool closedCompetitions = false;
// try to find if any competition could be settled at this moment

{
Expand Down Expand Up @@ -3193,6 +3409,7 @@ CheckBackupTracesBeforeSwapping
for (vint i = 0; i < concurrentCount; i++)
{
auto trace = EnsureTraceWithValidStates(backupTraces->Get(i));
auto attendingCompetitions = trace->competitionRouting.attendingCompetitions;
auto* pnext = &trace->competitionRouting.attendingCompetitions;
while (*pnext != nullref)
{
Expand All @@ -3206,7 +3423,15 @@ CheckBackupTracesBeforeSwapping
pnext = &ac->nextActiveAC;
}
}

if (trace->competitionRouting.attendingCompetitions != attendingCompetitions)
{
// only check the head node since this could trigger merging
closedCompetitions = true;
}
}

return closedCompetitions;
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions Import/VlppGlrParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,10 @@ IAstInsReceiver (Code Generation Templates)
Ptr<ParsingAstBase> AssemblerResolveAmbiguity(vint32_t type, collections::Array<Ptr<ParsingAstBase>>& candidates, const wchar_t* cppTypeName)
{
auto ast = Ptr(new TAmbiguity());
if (candidates.Count() > 0)
{
ast->codeRange = candidates[0]->codeRange;
}
for (auto candidate : candidates)
{
if (auto typedAst = candidate.Cast<TElement>())
Expand Down Expand Up @@ -2287,13 +2291,14 @@ TraceManager
// Ambiguity
Trace* EnsureTraceWithValidStates(Trace* trace);
bool AreTwoEndingInputTraceEqual(Trace* newTrace, Trace* candidate);
void MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate);
Trace* MergeTwoEndingInputTrace(Trace* newTrace, Trace* candidate);
void TryMergeSurvivingTraces();

// Competition
void AttendCompetition(Trace* trace, Ref<AttendingCompetitions>& newAttendingCompetitions, Ref<AttendingCompetitions>& newCarriedCompetitions, Ref<ReturnStack> returnStack, vint32_t ruleId, vint32_t clauseId, bool forHighPriority);
void AttendCompetitionIfNecessary(Trace* trace, vint32_t currentTokenIndex, EdgeDesc& edgeDesc, Ref<AttendingCompetitions>& newAttendingCompetitions, Ref<AttendingCompetitions>& newCarriedCompetitions, Ref<ReturnStack>& newReturnStack);
void CheckAttendingCompetitionsOnEndingEdge(Trace* trace, EdgeDesc& edgeDesc, Ref<AttendingCompetitions> acId, Ref<ReturnStack> returnStack);
void CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex);
bool CheckBackupTracesBeforeSwapping(vint32_t currentTokenIndex);

// ReturnStack
ReturnStackSuccessors* GetCurrentSuccessorInReturnStack(Ref<ReturnStack> base, vint32_t currentTokenIndex);
Expand Down
Loading

0 comments on commit 562d572

Please sign in to comment.