namespace HeuristicLab.Problems.ProgramSynthesis.Push.Interpreter { using System; using System.Collections.Generic; #if DEBUG #endif using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using HeuristicLab.Core; using HeuristicLab.Problems.ProgramSynthesis.Push.Configuration; using HeuristicLab.Problems.ProgramSynthesis.Push.Expressions; using HeuristicLab.Problems.ProgramSynthesis.Push.Parser; using HeuristicLab.Problems.ProgramSynthesis.Push.Stack; using HeuristicLab.Random; public class PushInterpreter : IPushInterpreter { private Task currentTask; public PushInterpreter(IReadOnlyPushConfiguration config = null, IRandom random = null, InterpreterPoolContainer poolContainer = null) { Random = random ?? new FastRandom(); Configuration = config ?? new PushConfiguration(); // setting the capacity of the stacks to max points ensures that there will be enough memory at runtime ExecStack = new PushStack(Configuration.EvalPushLimit); CodeStack = new PushStack(Configuration.EvalPushLimit) { IsEnabled = Configuration.IsCodeStackEnabled }; NameStack = new PushStack { IsEnabled = Configuration.IsNameStackEnabled }; BooleanStack = new PushStack { IsEnabled = Configuration.IsBooleanStackEnabled }; IntegerStack = new PushStack { IsEnabled = Configuration.IsIntegerStackEnabled }; FloatStack = new PushStack { IsEnabled = Configuration.IsFloatStackEnabled }; CharStack = new PushStack { IsEnabled = Configuration.IsCharStackEnabled }; StringStack = new PushStack { IsEnabled = Configuration.IsStringStackEnabled }; CustomExpressions = new Dictionary(); PoolContainer = poolContainer ?? new InterpreterPoolContainer(); } public PushInterpreter(int seed, IReadOnlyPushConfiguration config = null) : this(config, new FastRandom(seed)) { } public IRandom Random { get; set; } public int ExecCounter { get; private set; } public bool IsPaused { get; private set; } public bool IsAborted { get; private set; } public bool IsRunning { get { return !ExecStack.IsEmpty && !IsPaused && !IsAborted && (ExecCounter < Configuration.EvalPushLimit); } } public bool IsCompleted { get { return ExecStack.Count == 0; } } public bool CanStep { get { return !IsCompleted && !IsAborted && IsPaused; } } public InterpreterPoolContainer PoolContainer { get; private set; } public IReadOnlyPushConfiguration Configuration { get; protected set; } public IStack CodeStack { get; private set; } public IStack ExecStack { get; private set; } public IStack NameStack { get; private set; } public IStack BooleanStack { get; private set; } public IStack IntegerStack { get; private set; } public IStack FloatStack { get; private set; } public IStack CharStack { get; private set; } public IStack StringStack { get; private set; } public IDictionary CustomExpressions { get; private set; } public bool IsNameQuoteFlagSet { get; set; } public Task RunAsync(string code, bool stepwise = false, CancellationToken token = default(CancellationToken)) { var program = PushParser.Parse(code); currentTask = RunAsync(program, stepwise, token); return currentTask; } public async Task RunAsync( Expression expression, bool stepwise = false, CancellationToken token = default(CancellationToken)) { await Task.Run(() => Run(expression, stepwise), token); } public void Run(string code, bool stepwise = false) { var program = PushParser.Parse(code); Run(program, stepwise); } public void Run(Expression program, bool stepwise = false) { PoolContainer.CreatePools(); IsPaused = stepwise; /* Push top expression so the loop is able to enter * If the top expression is a single statement then the loop has nothing to do * Otherwise the expand expression will be evaluated and pushes code onto the EXEC stack */ ExecStack.Push(program); if (Configuration.TopLevelPushCode) CodeStack.Insert(0, program); // run top expression DoStep(); Interpret(); PoolContainer.DisposePools(); } public async Task AbortAsync() { if (IsAborted || IsCompleted) return; IsAborted = true; PoolContainer.DisposePools(); if (currentTask != null) await currentTask; } public async Task AbortAndResetAsync() { await AbortAsync(); Reset(); } public async Task PauseAsync() { if (IsPaused || IsCompleted) return; IsPaused = true; if (currentTask != null) await currentTask; } public async Task ResumeAsync() { if (IsPaused || !IsAborted) { IsPaused = false; await InterpretAsync(); } else await currentTask; } public void Resume() { if (!IsPaused && IsAborted) return; IsPaused = false; Interpret(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Step() { if (!CanStep) return false; var successful = DoStep(); Finally(); return successful; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Step(int count) { for (var i = 0; i < count; i++) Step(); } public void PrintStacks() { PrintStack("EXEC", ExecStack); PrintStack("CODE", CodeStack); PrintStack("NAME", NameStack); PrintStack("BOOLEAN", BooleanStack); PrintStack("FLOAT", FloatStack); PrintStack("INTEGER", IntegerStack); if (CustomExpressions.Count > 0) { Console.WriteLine("--------- Custom Expressions ---------"); foreach (var ce in CustomExpressions) { Console.WriteLine("{0}: {1}", ce.Key, ce.Value); } } } /// /// Clears stacks /// public void Reset() { IsAborted = false; IsPaused = false; currentTask = null; Clear(); } /// /// Clears stacks /// public void Clear() { ExecCounter = 0; ExecStack.Clear(); CodeStack.Clear(); NameStack.Clear(); BooleanStack.Clear(); IntegerStack.Clear(); FloatStack.Clear(); CustomExpressions.Clear(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Interpret() { while (IsRunning) { DoStep(); ExecCounter++; } Finally(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Finally() { if (!IsCompleted) return; if (Configuration.TopLevelPopCode && (CodeStack.Count > 0)) CodeStack.Pop(); } #if DEBUG private Expression last; private bool DoStep() { var expression = ExecStack.Pop(); //if (ExecStack.Any(e => e == null)) { // throw new InvalidProgramException(); //} var succ = expression.Eval(this); //last = expression; return succ; } #else [MethodImpl(MethodImplOptions.AggressiveInlining)] private bool DoStep() { return ExecStack.Pop().Eval(this); } #endif private Task InterpretAsync() { currentTask = Task.Run(() => Interpret()); return currentTask; } private void PrintStack(string name, IStack stack) { if (stack.IsEmpty) return; Console.WriteLine("--------- {0} ---------\n{1}\n", name, stack); } } }