Skip to content

Instantly share code, notes, and snippets.

@SaxxonPike
Created December 31, 2018 04:02
Show Gist options
  • Save SaxxonPike/b0d539d3caaca79e727be51917493de3 to your computer and use it in GitHub Desktop.
Save SaxxonPike/b0d539d3caaca79e727be51917493de3 to your computer and use it in GitHub Desktop.
BMS random/if/switch block handler in RhythmCodex
private IEnumerable<BmsCommand> ResolveScope(IEnumerable<BmsCommand> commands, BmsResolverScope scope,
bool isRootScope)
{
var pendingScopeCommands = new List<BmsCommand>();
var pendingScope = new BmsResolverScope();
var scopeLevel = 0;
foreach (var command in commands)
{
// Ending any block will evaluate it when the scope level returns to zero.
if ("endif".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"endsw".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"elseif".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"else".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
if (scopeLevel > 0)
{
scopeLevel--;
if (scopeLevel == 0)
{
var topCommand = pendingScopeCommands.First();
if ("switch".Equals(topCommand.Name, StringComparison.OrdinalIgnoreCase) ||
(topCommand.Value == null && !scope.Satisfied) ||
(topCommand.Value != null && scope.CompareValue == topCommand.Value))
{
scope.Satisfied = true;
var innerScopeCommands = pendingScopeCommands.Skip(1).ToArray();
Console.WriteLine("Processing inner scope:");
Console.WriteLine(string.Join(Environment.NewLine, innerScopeCommands.Select(isc => $"{isc}")));
var innerScopeOutput =
ResolveScope(innerScopeCommands, pendingScope, false).ToArray();
foreach (var innerCommand in innerScopeOutput)
yield return innerCommand;
}
pendingScopeCommands.Clear();
pendingScope = new BmsResolverScope();
}
if ("endif".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"endsw".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
scope.Satisfied = false;
if (scopeLevel == 0)
continue;
}
}
}
// Starting a block will prepare a scope.
if ("if".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"elseif".Equals(command.Name, StringComparison.OrdinalIgnoreCase) ||
"else".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
if (scopeLevel == 0)
{
pendingScope.CompareValue = scope.CompareValue;
pendingScope.Matched = true;
}
scopeLevel++;
}
if ("switch".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
if (scopeLevel == 0)
{
pendingScope.CompareValue = $"{_randomizer.GetInt(int.Parse(command.Value)) + 1}";
pendingScope.Matched = false;
}
scopeLevel++;
}
// Skip scope processing if we are figuring out an inner scope.
if (scopeLevel > 0)
{
pendingScopeCommands.Add(command);
continue;
}
// Scope specific commands.
if (!isRootScope)
{
if ("case".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
if (command.Value == scope.CompareValue)
scope.Matched = true;
continue;
}
if ("def".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
scope.Matched = true;
continue;
}
if (scope.Matched && "skip".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
yield break;
}
if ("random".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
scope.CompareValue = $"{_randomizer.GetInt(int.Parse(command.Value)) + 1}";
continue;
}
if ("setrandom".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
scope.CompareValue = command.Value;
continue;
}
if ("endrandom".Equals(command.Name, StringComparison.OrdinalIgnoreCase))
{
scope.CompareValue = "1";
continue;
}
if (isRootScope || scope.Matched)
yield return command;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment