Skip to content

Commit

Permalink
feat: Bind Query Scope and Filter, Effect Target (#105)
Browse files Browse the repository at this point in the history
* feat: Bind Scope and Filter symbols of a Query

part of: Implement Logic in Symbol layer #44

* feat: make characteristics Resources of a Profile

* feat: bind Effect.TargetMember

* refactor: move around code in Playground Main

* fix: bind members in category links

* fix: deduplicate characteristics in Profile.Members (fixup)

* fix: additional fixes and optimizations for TargetMember binding

* refactor: group Playground diagnostics by message

* fix: shorten lookup on success when descending

* feat: fully bind TargetMember (including link target members)

* feat: optimize CategoryEntry binding

* feat: optimize type checks (maybe)

* feat: optimize lookup in descendants
  • Loading branch information
amis92 authored Mar 9, 2023
1 parent 4a476e0 commit 789d9c3
Show file tree
Hide file tree
Showing 17 changed files with 420 additions and 161 deletions.
22 changes: 14 additions & 8 deletions src/Phalanx.PlaygroundTool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@ namespace Phalanx.PlaygroundTool;

class Program
{
static void PlayWithSample()
static void Main()
{
Console.WriteLine("📌 SampleDataset");
PlayWithSampleDataset();
Console.WriteLine("-----------------------------------");
Console.WriteLine();
Console.WriteLine("📌 Playground inline dataset");
PlayWithRosterChanging();
}

static void PlayWithSampleDataset()
{
Console.WriteLine("Loading sample dataset:");
var ws = SampleDataResources.CreateXmlWorkspace();
Expand All @@ -29,20 +39,16 @@ static void PlayWithSample()
watch.Stop();
var diagTime = watch.Elapsed;
Console.WriteLine("Diagnosed in " + diagTime);
foreach (var diagnostic in diagnostics)
foreach (var diagnosticBin in diagnostics.GroupBy(x => x.ToString()))
{
Console.WriteLine(diagnostic.ToString());
Console.WriteLine($"{diagnosticBin.Count()}x {diagnosticBin.Key}");
}
Console.WriteLine($"Diagnostic count: {diagnostics.Length}");
Console.WriteLine("Finished processing sample dataset.");
}

static void Main()
static void PlayWithRosterChanging()
{
PlayWithSample();
Console.WriteLine("-----------------------------------");
Console.WriteLine();

Console.WriteLine(">>> Building dataset.");
// create
var rosterState = RosterState.CreateFromNodes(GetDataset());
Expand Down
230 changes: 138 additions & 92 deletions src/WarHub.ArmouryModel.Concrete.Extensions/Binder.cs

Large diffs are not rendered by default.

97 changes: 88 additions & 9 deletions src/WarHub.ArmouryModel.Concrete.Extensions/BinderFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ public BinderFactoryVisitor(BinderFactory factory, ISymbol? containingSymbol)

public override Binder DefaultVisit(SourceNode node)
{
// no support for detached nodes (e.g. withoug root like roster or catalogue node)
// can we add such support?
return node.Parent is { } parent ? VisitCore(parent) : Compilation.GlobalNamespaceBinder;
return GetParentBinder(node);
}

public override Binder Visit(SourceNode? node)
Expand All @@ -55,27 +53,95 @@ private Binder VisitCore(SourceNode? node)
return node!.Accept(this)!;
}

private Binder GetParentBinder(SourceNode node)
{
// no support for detached nodes (e.g. withoug root like roster or catalogue node)
// can we add such support?
return node.Parent is { } parent ? VisitCore(parent) : Compilation.GlobalNamespaceBinder;
}

public override Binder VisitRoster(RosterNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
return new RosterBinder(next, GetRosterSymbol(node));
}

public override Binder VisitCatalogue(CatalogueNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
return new CatalogueBaseBinder(next, GetCatalogueSymbol(node));
}

public override Binder VisitGamesystem(GamesystemNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
return new CatalogueBaseBinder(next, GetCatalogueSymbol(node));
}

public override Binder VisitCategoryEntry(CategoryEntryNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitCategoryLink(CategoryLinkNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitEntryLink(EntryLinkNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitForceEntry(ForceEntryNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitInfoGroup(InfoGroupNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitInfoLink(InfoLinkNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitProfile(ProfileNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitRule(RuleNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitSelectionEntry(SelectionEntryNode node)
{
return VisitEntryCore(node);
}

public override Binder VisitSelectionEntryGroup(SelectionEntryGroupNode node)
{
return VisitEntryCore(node);
}

private Binder VisitEntryCore(EntryBaseNode node)
{
var next = GetParentBinder(node);
var containingEntry = GetContainingEntry(next, node);
if (containingEntry is not null)
{
next = new EntryBinder(containingEntry, next);
}
return next;
}

public override Binder VisitCharacteristic(CharacteristicNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
if (GetAncestorSymbol<ProfileSymbol>(node) is { } profile)
{
return new CharacteristicBinder(next, profile, profile.Type);
Expand All @@ -89,14 +155,14 @@ public override Binder VisitCharacteristic(CharacteristicNode node)

public override Binder VisitForce(ForceNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
var symbol = GetAncestorSymbol<ForceSymbol>(node);
return symbol is null ? next : new ForceBinder(next, symbol);
}

public override Binder VisitSelection(SelectionNode node)
{
var next = DefaultVisit(node);
var next = GetParentBinder(node);
var symbol = GetAncestorSymbol<SelectionSymbol>(node);
return symbol is null ? next : new SelectionBinder(next, symbol);
}
Expand All @@ -107,6 +173,19 @@ private CatalogueBaseSymbol GetCatalogueSymbol(CatalogueBaseNode node) =>
private RosterSymbol GetRosterSymbol(RosterNode node) =>
GetAncestorModule<RosterSymbol>(node);

private static EntrySymbol? GetContainingEntry(Binder outerBinder, SourceNode node)
{
foreach (var item in outerBinder.ContainingSymbol!.GetMembers())
{
if (item.Kind is SymbolKind.ResourceEntry or SymbolKind.ContainerEntry
&& item is EntrySymbol entry && ReferenceEquals(entry.Declaration, node))
{
return entry;
}
}
return null;
}

private T? GetAncestorSymbol<T>(SourceNode node) where T : Symbol
{
return _(containingSymbol);
Expand Down
19 changes: 16 additions & 3 deletions src/WarHub.ArmouryModel.Concrete.Extensions/CatalogueBaseBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ internal CatalogueBaseBinder(Binder next, CatalogueBaseSymbol catalogue) : base(

internal override Symbol? ContainingSymbol => Catalogue;

internal override ContainerEntryBaseSymbol? ContainingContainerSymbol => null;

internal override EntrySymbol? ContainingEntrySymbol => null;

internal override ForceSymbol? ContainingForceSymbol => null;

internal override SelectionSymbol? ContainingSelectionSymbol => null;

public ImmutableArray<ICatalogueSymbol> RootClosure => lazyRootClosure ??= CalculateRootClosure(Catalogue);

internal override void LookupSymbolsInSingleBinder(
Expand All @@ -21,16 +29,21 @@ internal override void LookupSymbolsInSingleBinder(
LookupOptions options,
Binder originalBinder,
bool diagnose,
ISymbol? qualifier)
Symbol? qualifier)
{
if (options.HasFlag(LookupOptions.CatalogueOnly))
{
// no catalogues to bind here
return;
}
if (qualifier is IEntrySymbol entrySymbol)
if (options.HasFlag(LookupOptions.EntryMembersOnly))
{
// we're too deep, should've bound in entry binders
return;
}
if (qualifier is EntrySymbol entrySymbol)
{
LookupSymbolInQualifyingEntry(entrySymbol, result, symbolId, options, originalBinder, diagnose, RootClosure);
LookupSymbolsInQualifyingEntry(entrySymbol, result, symbolId, options, originalBinder, diagnose, RootClosure);
if (result.IsMultiViable)
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ internal override void LookupSymbolsInSingleBinder(
LookupOptions options,
Binder originalBinder,
bool diagnose,
ISymbol? qualifier)
Symbol? qualifier)
{
if (options.CanConsiderResourceDefinitions())
{
Expand Down
23 changes: 23 additions & 0 deletions src/WarHub.ArmouryModel.Concrete.Extensions/EntryBinder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace WarHub.ArmouryModel.Concrete;

internal class EntryBinder : Binder
{
public EntryBinder(EntrySymbol entrySymbol, Binder next) : base(next)
{
EntrySymbol = entrySymbol;
}

public EntrySymbol EntrySymbol { get; }

internal override Symbol? ContainingSymbol => EntrySymbol;

internal override EntrySymbol? ContainingEntrySymbol => EntrySymbol;

internal override void LookupSymbolsInSingleBinder(LookupResult result, string symbolId, LookupOptions options, Binder originalBinder, bool diagnose, Symbol? qualifier)
{
if (qualifier is EntrySymbol entrySymbol && ReferenceEquals(entrySymbol, EntrySymbol))
{
LookupSymbolsInQualifyingEntry(entrySymbol, result, symbolId, options, originalBinder, diagnose);
}
}
}
6 changes: 3 additions & 3 deletions src/WarHub.ArmouryModel.Concrete.Extensions/ForceBinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal override void LookupSymbolsInSingleBinder(
LookupOptions options,
Binder originalBinder,
bool diagnose,
ISymbol? qualifier)
Symbol? qualifier)
{
if (options.HasFlag(LookupOptions.CatalogueOnly))
{
Expand All @@ -40,9 +40,9 @@ internal override void LookupSymbolsInSingleBinder(
result.MergeEqual(LookupResult.Good(Compilation.NoCategoryEntrySymbol));
return;
}
if (qualifier is IEntrySymbol entrySymbol)
if (qualifier is EntrySymbol entrySymbol)
{
LookupSymbolInQualifyingEntry(entrySymbol, result, symbolId, options, originalBinder, diagnose, RootClosure);
LookupSymbolsInQualifyingEntry(entrySymbol, result, symbolId, options, originalBinder, diagnose, RootClosure);
if (result.IsMultiViable)
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ internal GamesystemNamespaceBinder(Binder next, SourceGlobalNamespaceSymbol name

internal override Symbol? ContainingSymbol => NamespaceSymbol;

internal override ContainerEntryBaseSymbol? ContainingContainerSymbol => null;

internal override EntrySymbol? ContainingEntrySymbol => null;

internal override ForceSymbol? ContainingForceSymbol => null;

internal override SelectionSymbol? ContainingSelectionSymbol => null;

public SourceGlobalNamespaceSymbol NamespaceSymbol { get; }

internal override void LookupSymbolsInSingleBinder(
Expand All @@ -18,7 +26,7 @@ internal override void LookupSymbolsInSingleBinder(
LookupOptions options,
Binder originalBinder,
bool diagnose,
ISymbol? qualifier)
Symbol? qualifier)
{
if (options.CanConsiderCatalogues())
{
Expand Down
55 changes: 55 additions & 0 deletions src/WarHub.ArmouryModel.Concrete.Extensions/GeneratedCostSymbol.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
namespace WarHub.ArmouryModel.Concrete;

internal class GeneratedCostSymbol : Symbol, ICostSymbol
{
public GeneratedCostSymbol(ISymbol? containingSymbol, IResourceDefinitionSymbol type)
{
ContainingSymbol = containingSymbol;
Type = type;
}

public override SymbolKind Kind => SymbolKind.ResourceEntry;

public override string? Id => null;

public override string Name => Type.Name;

public override string? Comment => null;

public override ISymbol? ContainingSymbol { get; }

public decimal Value => 0m;

public ResourceKind ResourceKind => ResourceKind.Cost;

public IResourceDefinitionSymbol Type { get; }

public IResourceEntrySymbol? ReferencedEntry => null;

public bool IsHidden => false;

public bool IsReference => false;

public IPublicationReferenceSymbol? PublicationReference => null;

public ImmutableArray<IEffectSymbol> Effects => ImmutableArray<IEffectSymbol>.Empty;

public ImmutableArray<IResourceEntrySymbol> Resources => ImmutableArray<IResourceEntrySymbol>.Empty;

IEntrySymbol? IEntrySymbol.ReferencedEntry => null;

public override void Accept(SymbolVisitor visitor)
{
visitor.VisitResourceEntry(this);
}

public override TResult Accept<TResult>(SymbolVisitor<TResult> visitor)
{
return visitor.VisitResourceEntry(this);
}

public override TResult Accept<TArgument, TResult>(SymbolVisitor<TArgument, TResult> visitor, TArgument argument)
{
return visitor.VisitResourceEntry(this, argument);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ protected override void BindReferencesCore(Binder binder, BindingDiagnosticBag d
}
else if (TargetKind is EffectTargetKind.Member)
{
lazyTargetMember = binder.BindEntryMemberSymbol(Declaration, Declaration.Field, diagnostics);
lazyTargetMember = binder.BindEffectTargetMemberSymbol(Declaration, Declaration.Field, diagnostics);
}
}
}
9 changes: 6 additions & 3 deletions src/WarHub.ArmouryModel.Concrete.Extensions/ProfileSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ IEnumerable<CharacteristicSymbol> CreateCharacteristics()

public ImmutableArray<CharacteristicSymbol> Characteristics { get; }

public override ImmutableArray<ResourceEntryBaseSymbol> Resources =>
Characteristics.Cast<CharacteristicSymbol, ResourceEntryBaseSymbol>();

ImmutableArray<IResourceEntrySymbol> IEntrySymbol.Resources =>
Characteristics.Cast<CharacteristicSymbol, IResourceEntrySymbol>();

ImmutableArray<ICharacteristicSymbol> IProfileSymbol.Characteristics =>
Characteristics.Cast<CharacteristicSymbol, ICharacteristicSymbol>();

Expand All @@ -41,7 +47,4 @@ protected override void BindReferencesCore(Binder binder, BindingDiagnosticBag d

lazyType = binder.BindProfileTypeSymbol(Declaration, diagnostics);
}

protected override ImmutableArray<Symbol> MakeAllMembers(BindingDiagnosticBag diagnostics) =>
base.MakeAllMembers(diagnostics).AddRange(Characteristics);
}
Loading

0 comments on commit 789d9c3

Please sign in to comment.