/* * Copyright © 2011, Petro Protsyk, Denys Vuika * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; namespace Scripting.SSharp.Execution.VM { using Operations; using Runtime; internal class ExecutableMachine { #region Fields private readonly List _commands = new List(); private int _current; private MachineFlags _flags; #endregion #region Registers public object AX { get; set; } public object BX { get; set; } public object DX { get; set; } public bool BBX { get; set; } //Should be read-only, see stack commands public readonly Stack Stack = new Stack(); internal protected int CommandCount { get { return _commands.Count; } } #endregion #region Properties public IOperation Current { get { if (_current >= 0 && _current < _commands.Count) return _commands[_current]; return null; } } #endregion #region Execution public void Reset() { _current = 0; _flags = MachineFlags.Clear; AX = null; BX = null; DX = null; BBX = false; Stack.Clear(); } public void Execute(IScriptContext context) { IOperation[] arCommands = _commands.ToArray(); while ((_flags & MachineFlags.Ret) != MachineFlags.Ret) _current += arCommands[_current].Execute(context); //NOTE: Peformance //while (!Test(MachineFlags.Ret)) // Step(context); Reset(); } public void Step(IScriptContext context) { if (Test(MachineFlags.Ret)) throw new MachineException("Ret command has been already executed, can't continue evaluation"); if (_current > _commands.Count - 1) throw new MachineException("Command execution flow exception"); _current += _commands[_current].Execute(context); } public bool Test(MachineFlags flag) { return (_flags & flag) == flag; } public void SetFlag(MachineFlags flag) { _flags |= flag; } public void ClearFlag(MachineFlags flag) { _flags ^= flag; } #endregion #region Operations readonly Dictionary _registeredOperations = new Dictionary(); public void RegisterOperation(Type operationType, IOperationBuilder builder) { _registeredOperations.Add(operationType, builder); } public void RegisterOperation(IOperationBuilder builder) where T : IOperation { RegisterOperation(typeof(T), builder); } public IOperation CreateOperation(Type operationType) { IOperation op = _registeredOperations[operationType].Create(); _commands.Add(op); return op; } public T CreateOperation() where T : IOperation { return (T)CreateOperation(typeof(T)); } #endregion #region Construction protected ExecutableMachine() { } public static ExecutableMachine Create() { var machine = new ExecutableMachine(); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); machine.RegisterOperation(new BaseOperationBuilder(machine)); return machine; } #endregion } [Flags] internal enum MachineFlags { Clear = 0, Ret = 1 << 0, Break = 1 << 1, Cond = 1 << 2 } [Flags] internal enum MachineRegisters { None = 0, /// /// Evaluation result register /// AX = 1 << 0, /// /// Evaluation parameter register /// BX = 1 << 1, /// /// Reserved evaluation register /// DX = 1 << 2, /// /// Boolean result register /// BBX = 1 << 3 } internal class MachineException : Exception { public MachineException(string message) : base(message) { } } }