-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This also implements stronger constraint types, to help give better control over sequencing.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
using System.Collections.Immutable; | ||
|
||
namespace nadena.dev.ndmf | ||
{ | ||
public class BuildPhase | ||
{ | ||
public string Name { get; } | ||
// Prevent extension for now | ||
internal BuildPhase(string name) | ||
{ | ||
Name = name; | ||
} | ||
|
||
public static readonly BuildPhase Resolving = new BuildPhase("Resolving"); | ||
public static readonly BuildPhase Generating = new BuildPhase("Generating"); | ||
public static readonly BuildPhase Transforming = new BuildPhase("Transforming"); | ||
public static readonly BuildPhase Optimizing = new BuildPhase("Optimizing"); | ||
|
||
public static readonly ImmutableList<BuildPhase> BuiltInPhases | ||
= ImmutableList.Create(Resolving, Generating, Transforming, Optimizing); | ||
|
||
public override string ToString() => Name; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
|
||
namespace nadena.dev.ndmf | ||
{ | ||
[AttributeUsage(AttributeTargets.Assembly)] | ||
public class ExportsPlugin : Attribute | ||
{ | ||
public Type PluginType { get; } | ||
|
||
public ExportsPlugin(Type pluginType) | ||
{ | ||
PluginType = pluginType; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using System; | ||
using System.Threading; | ||
using NUnit.Framework; | ||
|
||
namespace nadena.dev.ndmf.fluent | ||
{ | ||
internal interface IPass | ||
{ | ||
string QualifiedName { get; } | ||
string DisplayName { get; } | ||
|
||
PassKey PassKey { get; } | ||
bool IsPhantom { get; } | ||
|
||
void Execute(BuildContext context); | ||
} | ||
|
||
internal class AnonymousPass : IPass | ||
{ | ||
public string QualifiedName { get; } | ||
public string DisplayName { get; } | ||
|
||
private readonly InlinePass _executor; | ||
public PassKey PassKey => new PassKey(QualifiedName); | ||
|
||
internal bool IsPhantom { get; set; } | ||
bool IPass.IsPhantom => IsPhantom; | ||
|
||
public AnonymousPass(string qualifiedName, string displayName, InlinePass execute) | ||
{ | ||
QualifiedName = qualifiedName; | ||
DisplayName = displayName; | ||
_executor = execute; | ||
} | ||
|
||
public void Execute(BuildContext context) | ||
{ | ||
_executor(context); | ||
} | ||
} | ||
|
||
public abstract class Pass<T> : IPass where T : Pass<T>, new() | ||
{ | ||
private static Lazy<T> _instance = new Lazy<T>(() => new T(), | ||
LazyThreadSafetyMode.ExecutionAndPublication); | ||
|
||
public static T Instance => _instance.Value; | ||
|
||
PassKey IPass.PassKey => new PassKey(QualifiedName); | ||
|
||
public virtual string QualifiedName => typeof(T).FullName; | ||
public virtual string DisplayName => typeof(T).Name; | ||
bool IPass.IsPhantom => false; | ||
|
||
protected abstract void Execute(BuildContext context); | ||
|
||
// Prevent Pass handles from being used to execute passes arbitrarily by exposing it via an internal interface | ||
void IPass.Execute(BuildContext context) | ||
{ | ||
Execute(context); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace nadena.dev.ndmf.fluent | ||
{ | ||
internal class PassKey | ||
{ | ||
public readonly string QualifiedName; | ||
|
||
public PassKey(string qualifiedName) | ||
{ | ||
QualifiedName = qualifiedName; | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return QualifiedName; | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Threading; | ||
using nadena.dev.ndmf; | ||
|
||
namespace nadena.dev.ndmf.fluent | ||
{ | ||
internal interface IPlugin | ||
{ | ||
string QualifiedName { get; } | ||
string DisplayName { get; } | ||
|
||
void Configure(PluginInfo info); | ||
} | ||
|
||
public abstract class Plugin<T> : IPlugin where T: Plugin<T>, new() | ||
{ | ||
private static object _lock = new object(); | ||
private static Lazy<Plugin<T>> _instance = new Lazy<Plugin<T>>(() => new T(), | ||
LazyThreadSafetyMode.ExecutionAndPublication); | ||
|
||
public static Plugin<T> Instance => _instance.Value; | ||
|
||
private PluginInfo _info; | ||
|
||
public virtual string QualifiedName => typeof(T).FullName; | ||
public virtual string DisplayName => QualifiedName; | ||
|
||
void IPlugin.Configure(PluginInfo info) | ||
{ | ||
_info = info; | ||
try | ||
{ | ||
Configure(); | ||
} | ||
finally | ||
{ | ||
_info = null; | ||
} | ||
} | ||
|
||
protected abstract void Configure(); | ||
|
||
protected Sequence InPhase(BuildPhase phase) | ||
{ | ||
if (_info == null) | ||
{ | ||
throw new Exception("InPhase can only be called from within Configure()"); | ||
} | ||
|
||
return _info.NewSequence(phase); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using nadena.dev.ndmf.model; | ||
|
||
namespace nadena.dev.ndmf.fluent | ||
{ | ||
internal class PluginInfo | ||
{ | ||
private readonly SolverContext _solverContext; | ||
private readonly IPlugin _plugin; | ||
private int sequenceIndex = 0; | ||
|
||
public PluginInfo(SolverContext solverContext, IPlugin plugin) | ||
{ | ||
_solverContext = solverContext; | ||
_plugin = plugin; | ||
} | ||
|
||
internal Sequence NewSequence(BuildPhase phase) | ||
{ | ||
string sequencePrefix = _plugin.QualifiedName + "/sequence#" + sequenceIndex++; | ||
return new Sequence(phase, _solverContext, _plugin, sequencePrefix); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using nadena.dev.ndmf.model; | ||
|
||
namespace nadena.dev.ndmf.fluent | ||
{ | ||
public sealed partial class Sequence | ||
{ | ||
private List<Action<SolverPass>> _pendingDependencies = new List<Action<SolverPass>>(); | ||
|
||
private void OnNewPass(SolverPass pass) | ||
{ | ||
foreach (var dep in _pendingDependencies) | ||
{ | ||
dep(pass); | ||
} | ||
_pendingDependencies.Clear(); | ||
} | ||
|
||
public Sequence BeforePlugin(string QualifiedName, string sourceFile = "", int sourceLine = 0) | ||
{ | ||
_solverContext.Constraints.Add(new Constraint() | ||
{ | ||
First = _sequenceEnd.PassKey, | ||
Second = _solverContext.GetPluginPhases(_phase, QualifiedName).PluginStart.PassKey, | ||
Type = ConstraintType.WeakOrder, | ||
DeclaredFile = sourceFile, | ||
DeclaredLine = sourceLine, | ||
}); | ||
|
||
return this; | ||
} | ||
|
||
public Sequence BeforePlugin<T>(T plugin, string sourceFile = "", int sourceLine = 0) where T : fluent.Plugin<T>, new() | ||
{ | ||
return BeforePlugin(plugin.QualifiedName, sourceFile, sourceLine); | ||
} | ||
|
||
public Sequence AfterPlugin(string qualifiedName, string sourceFile = "", int sourceLine = 0) | ||
{ | ||
_solverContext.Constraints.Add(new Constraint() | ||
{ | ||
First = _solverContext.GetPluginPhases(_phase, qualifiedName).PluginEnd.PassKey, | ||
Second = _sequenceStart.PassKey, | ||
Type = ConstraintType.WeakOrder, | ||
DeclaredFile = sourceFile, | ||
DeclaredLine = sourceLine, | ||
}); | ||
|
||
return this; | ||
} | ||
|
||
public Sequence AfterPlugin<T>(T plugin, string sourceFile = "", int sourceLine = 0) where T : Plugin<T>, new() | ||
{ | ||
return AfterPlugin(plugin.QualifiedName, sourceFile, sourceLine); | ||
} | ||
|
||
public Sequence WaitFor<T>(T pass, string sourceFile = "", int sourceLine = 0) where T : fluent.Pass<T>, new() | ||
{ | ||
_pendingDependencies.Add(nextPass => | ||
{ | ||
_solverContext.Constraints.Add(new Constraint() | ||
{ | ||
First = ((IPass) pass).PassKey, | ||
Second = nextPass.PassKey, | ||
Type = ConstraintType.WaitFor, | ||
DeclaredFile = sourceFile, | ||
DeclaredLine = sourceLine, | ||
}); | ||
}); | ||
|
||
return this; | ||
} | ||
|
||
public Sequence AfterPass(string qualifiedName, string sourceFile = "", int sourceLine = 0) | ||
{ | ||
_pendingDependencies.Add(nextPass => | ||
{ | ||
_solverContext.Constraints.Add(new Constraint() | ||
{ | ||
First = nextPass.PassKey, | ||
Second = _solverContext.Passes.Find(p => p.PassKey.QualifiedName == qualifiedName).PassKey, | ||
Type = ConstraintType.WeakOrder, | ||
DeclaredFile = sourceFile, | ||
DeclaredLine = sourceLine, | ||
}); | ||
}); | ||
|
||
return this; | ||
} | ||
|
||
public Sequence AfterPass<T>(T pass, string sourceFile = "", int sourceLine = 0) where T : Pass<T>, new() | ||
{ | ||
return AfterPass(pass.QualifiedName, sourceFile, sourceLine); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.