using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Threading; using csmic.Scripting; using System.Runtime.Remoting.Messaging; namespace csmic { /// /// A builder object that executes macro scripts. /// public class MacroBuilder { #region Members /// /// The input inputInterpreter. /// private InputInterpreter interpreter; /// The script to run as a macro. private string script; /// /// The output as a list of strings. /// private List output; /// /// The time for execution. /// private TimeSpan executionTime; /// /// The root macro operation. /// private MacroOperation rootOperation; #endregion #region Constructor /// /// Creates a new builder object that executes a given macro script. /// /// A list of strings representing the macro. /// The InputInterpreter to be used. public MacroBuilder(string script, InputInterpreter inputInterpreter) { this.output = new List(); this.executionTime = new TimeSpan(); this.script = script; this.interpreter = inputInterpreter; } /// /// Creates a new builder object that executes a given macro script. /// /// A list of strings representing the macro. /// The InputInterpreter to be used. internal MacroBuilder(MacroOperation script, InputInterpreter inputInterpreter) { this.output = new List(); this.executionTime = new TimeSpan(); DateTime timeStart = DateTime.Now; this.interpreter = inputInterpreter; this.rootOperation = script; ExecuteOperation(this.rootOperation); DateTime timeEnd = DateTime.Now; this.executionTime = timeEnd - timeStart; } #endregion #region Properties /// /// Gets a list of strings representing the output. /// public List Output { get { return this.output; } } /// /// Gets the execution time of the last script computation. /// public TimeSpan LastExecutionTime { get { return this.executionTime; } } /// /// Gets the decimal value last computed by the macrobuilder. /// public string FinalOutput { get { return this.interpreter.Output; } } #endregion #region Public Methods /// Runs this macro. public void Run() { DateTime timeStart = DateTime.Now; ASCIIEncoding encoder = new ASCIIEncoding(); Parser p = new Parser(new Scanner(new MemoryStream(encoder.GetBytes(this.script)))); p.Parse(); this.rootOperation = p.Root; ExecuteOperation(p.Root); DateTime timeEnd = DateTime.Now; this.executionTime = timeEnd - timeStart; } #endregion #region Private Methods private void ExecuteOperation(MacroOperation operation) { switch (operation.OperationType) { case OperationType.If: if (operation.Input.Count == 1) { this.interpreter.Interpret(operation.Input[0]); if (this.interpreter.Decimal == 1) { foreach (MacroOperation op in operation.Children) { ExecuteOperation(op); } } } break; case OperationType.Else: foreach (MacroOperation op in operation.Children) { ExecuteOperation(op); } break; case OperationType.IfElse: if (operation.Children.Count == 2 && operation.Children[0].Input.Count == 1) { MacroOperation ifOp = operation.Children[0]; MacroOperation elseOp = operation.Children[1]; this.interpreter.Interpret(ifOp.Input[0]); if (this.interpreter.Decimal == 1) { foreach (MacroOperation op in ifOp.Children) { ExecuteOperation(op); } } else { foreach (MacroOperation op in elseOp.Children) { ExecuteOperation(op); } } } break; case OperationType.While: if (operation.Input.Count == 1) { this.interpreter.Interpret(operation.Input[0]); while (this.interpreter.Decimal == 1) { foreach (MacroOperation op in operation.Children) { ExecuteOperation(op); } this.interpreter.Interpret(operation.Input[0]); } } break; case OperationType.For: if (operation.Input.Count == 3) { this.interpreter.Interpret(operation.Input[0]); this.interpreter.Interpret(operation.Input[1]); int loopCount = this.interpreter.Int; while (this.interpreter.Int == 1) { foreach (MacroOperation op in operation.Children) { ExecuteOperation(op); } this.interpreter.Interpret(operation.Input[2]); this.interpreter.Interpret(operation.Input[1]); } } break; case OperationType.FunctionDeclaration: if (operation.Input.Count > 1) { string name = operation.Input[0]; operation.Input.RemoveAt(0); StringBuilder builder = new StringBuilder(); operation.OperationType = OperationType.Unknown; InterpretedFunction function = new InterpretedFunction(name, operation, operation.Input.ToArray()); if (this.interpreter.InterpretedFunctions.Contains(function)) { this.interpreter.InterpretedFunctions[this.interpreter.InterpretedFunctions.IndexOf(function)] = function; } else { this.interpreter.InterpretedFunctions.Add(function); } } break; case OperationType.Echo: if (operation.Children.Count == 1) { MacroOperation op = operation.Children[0]; if (op.OperationType == OperationType.Statement) { this.interpreter.Interpret(op.Input[0]); this.output.Add(this.interpreter.Output); } } break; case OperationType.Say: if (operation.Input.Count == 1) { this.output.Add(operation.Input[0]); } break; case OperationType.Display: StringBuilder sb = new StringBuilder(); foreach (MacroOperation op in operation.Children) { if (op.OperationType == OperationType.Statement) { if (op.Input.Count == 1) { this.interpreter.Interpret(op.Input[0]); sb.Append(this.interpreter.Output); } } else if (op.OperationType == OperationType.String) { if (op.Input.Count == 1) { sb.Append(op.Input[0]); } } } this.output.Add(sb.ToString()); break; case OperationType.Statement: if (operation.Input.Count == 1) { this.interpreter.Interpret(operation.Input[0]); } break; case OperationType.String: //Should not reach this state. break; case OperationType.Unknown: if (operation.Children.Count > 0) { foreach (MacroOperation op in operation.Children) { ExecuteOperation(op); } } break; default: //CRAP. break; } } #endregion #region Asynchronous /// Executes the asynchronous operation. /// The input. /// The callback. public void RunAsync(string input, Action callback) { MacroAsyncDelegate del = new MacroAsyncDelegate(RunAsyncThreadingWork); del.BeginInvoke(input, (result) => { AsyncResult returned = result as AsyncResult; if (returned != null) { MacroAsyncDelegate end = returned.AsyncDelegate as MacroAsyncDelegate; if (end != null) { MacroBuilder returnValue = end.EndInvoke(result); callback(returnValue); } } }, null); } /// Executes the asynchronous threading work operation. /// The input. /// . private MacroBuilder RunAsyncThreadingWork(string input) { Run(); return this; } /// Macro asynchronous delegate. /// The input. /// . private delegate MacroBuilder MacroAsyncDelegate(string input); #endregion } }