/*
This file is part of ContrAlto.
ContrAlto is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ContrAlto is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with ContrAlto. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using System.IO;
namespace Contralto.Scripting
{
public class MethodInvokeInfo
{
public MethodInvokeInfo(MethodInfo method, object instance)
{
if (method == null || instance == null)
{
throw new ArgumentNullException("method and instance must be non-null");
}
Method = method;
Instance = instance;
}
public MethodInfo Method;
public object Instance;
}
///
/// Defines a node in the debug command tree.
///
public class DebuggerCommand
{
public DebuggerCommand(string name, String description, String usage, MethodInvokeInfo methodInvoke)
{
Name = name.Trim().ToLower();
Description = description;
Usage = usage;
Methods = new List(4);
if (methodInvoke != null)
{
Methods.Add(methodInvoke);
}
SubCommands = new List();
}
public string Name;
public string Description;
public string Usage;
public List Methods;
public List SubCommands;
public override string ToString()
{
if (this.Methods.Count == 0)
{
return String.Format("{0}... ({1})", this.Name, this.SubCommands.Count);
}
else
{
return this.Name;
}
}
public void AddSubNode(List words, MethodInvokeInfo methodInfo)
{
// We should never hit this case.
if (words.Count == 0)
{
throw new InvalidOperationException("Out of words building command node.");
}
// Check the root to see if a node for the first incoming word has already been added
DebuggerCommand subNode = FindSubNodeByName(words[0]);
if (subNode == null)
{
// No, it has not -- create one and add it now.
subNode = new DebuggerCommand(words[0], null, null, null);
this.SubCommands.Add(subNode);
if (words.Count == 1)
{
// This is the last stop -- set the method and be done with it now.
subNode.Methods.Add(methodInfo);
// early return.
return;
}
}
else
{
// The node already exists, we will be adding a subnode, hopefully.
if (words.Count == 1)
{
//
// If we're on the last word at this point then this is an overloaded command.
// Check that we don't have any other commands with this number of arguments.
//
int argCount = methodInfo.Method.GetParameters().Length;
foreach (MethodInvokeInfo info in subNode.Methods)
{
if (info.Method.GetParameters().Length == argCount)
{
throw new InvalidOperationException("Duplicate overload for console command");
}
}
//
// We're ok. Add it to the method list.
//
subNode.Methods.Add(methodInfo);
// and return early.
return;
}
}
// We have more words to go.
words.RemoveAt(0);
subNode.AddSubNode(words, methodInfo);
}
public DebuggerCommand FindSubNodeByName(string name)
{
DebuggerCommand found = null;
foreach (DebuggerCommand sub in SubCommands)
{
if (sub.Name == name)
{
found = sub;
break;
}
}
return found;
}
}
public enum CommandResult
{
Normal,
Quit,
QuitNoSave,
}
public class CommandExecutor
{
public CommandExecutor(params object[] commandObjects)
{
List