protected void runProgram(string program, Dictionary <string, object> variablesIn, int expectedIterations, out FrameContext context) { var inputStream = new AntlrInputStream(program); var lexer = new CloacaLexer(inputStream); CommonTokenStream commonTokenStream = new CommonTokenStream(lexer); var errorListener = new ParseErrorListener(); var parser = new CloacaParser(commonTokenStream); parser.AddErrorListener(errorListener); var antlrVisitorContext = parser.file_input(); Assert.That(errorListener.Errors.Count, Is.Zero, "There were parse errors:\n" + errorListener.Report()); var visitor = new CloacaBytecodeVisitor(variablesIn); visitor.Visit(antlrVisitorContext); // We'll do a disassembly here but won't assert against it. We just want to make sure it doesn't crash. CodeObject compiledProgram = visitor.RootProgram.Build(); Dis.dis(compiledProgram); // TODO: This dependency association is kind of gross. It's almost circular and is broken by assigning // the interpreter reference to the schedular after its initial constructor. var scheduler = new Scheduler(); var interpreter = new Interpreter(scheduler); // Create native resource manager which will handle builtins that provide access to 'native' resources such as files. var nativeResourceManager = new NativeResourceManager(); nativeResourceManager.RegisterProvider <INativeFileProvider>(new DefaultFileProvider()); nativeResourceManager.RegisterBuiltins(interpreter); interpreter.DumpState = true; scheduler.SetInterpreter(interpreter); var receipt = scheduler.Schedule(compiledProgram); context = receipt.Frame; foreach (string varName in variablesIn.Keys) { context.SetVariable(varName, variablesIn[varName]); } // Waiting on the task makes sure we get punched in the face by any exceptions it throws. // But they'll come rolling in as AggregateExceptions so we'll have to unpack them. var scheduler_task = scheduler.RunUntilDone(); scheduler_task.Wait(); Assert.That(receipt.Completed); if (receipt.EscapedExceptionInfo != null) { receipt.EscapedExceptionInfo.Throw(); } Assert.That(scheduler.TickCount, Is.EqualTo(expectedIterations)); }
/// <summary> /// Evaluates the given input and will trigger WhenReplCommandDone when it has finished. The data passed to that /// event will include the result of evaluating the input--whether it was successful or unsuccessful. /// /// Look at InterpretAsync if you'd like to receive the text output directly and block until evaluation has /// completely finished. /// </summary> /// <param name="input">The code to interpret. Note that REPL code should have a trailing newline.</param> public void Interpret(string input) { CaughtError = false; var inputStream = new AntlrInputStream(input); var lexer = new CloacaLexer(inputStream); CommonTokenStream commonTokenStream = new CommonTokenStream(lexer); errorListener.Clear(); var parser = new CloacaParser(commonTokenStream); parser.AddErrorListener(errorListener); var antlrVisitorContext = parser.single_input(); if (errorListener.Errors.Count > 0) { CaughtError = true; StringBuilder errorBuilder = new StringBuilder("There were errors trying to compile the script. We cannot run it:" + Environment.NewLine); foreach (var error in errorListener.Errors) { errorBuilder.Append(error); errorBuilder.Append(Environment.NewLine); } WhenReplCommandDone(this, errorBuilder.ToString()); return; } else if (errorListener.ExpectedMoreText) { WhenReplCommandDone(this, "..."); return; } if (ContextVariables == null) { ContextVariables = new Dictionary <string, object>(); } var visitor = new CloacaBytecodeVisitor(ContextVariables); visitor.Visit(antlrVisitorContext); CodeObject compiledProgram = visitor.RootProgram.Build(); var scheduledTaskRecord = Scheduler.Schedule(compiledProgram); activeContext = scheduledTaskRecord.Frame; scheduledTaskRecord.WhenTaskCompleted += WhenReplTaskCompleted; scheduledTaskRecord.WhenTaskExceptionEscaped += WhenReplTaskExceptionEscaped; foreach (string varName in ContextVariables.Keys) { activeContext.SetVariable(varName, ContextVariables[varName]); } Run(); }
protected void runProgram(string program, Dictionary <string, object> variablesIn, List <ISpecFinder> moduleSpecFinders, int expectedIterations, out FrameContext context) { CodeObject compiledProgram = null; try { compiledProgram = ByteCodeCompiler.Compile(program, variablesIn); } catch (CloacaParseException parseFailed) { Assert.Fail(parseFailed.Message); } Dis.dis(compiledProgram); // TODO: This dependency association is kind of gross. It's almost circular and is broken by assigning // the interpreter reference to the schedular after its initial constructor. var scheduler = new Scheduler(); var interpreter = new Interpreter(scheduler); interpreter.DumpState = true; foreach (var finder in moduleSpecFinders) { interpreter.AddModuleFinder(finder); } scheduler.SetInterpreter(interpreter); var receipt = scheduler.Schedule(compiledProgram); context = receipt.Frame; foreach (string varName in variablesIn.Keys) { context.SetVariable(varName, variablesIn[varName]); } // Waiting on the task makes sure we get punched in the face by any exceptions it throws. // But they'll come rolling in as AggregateExceptions so we'll have to unpack them. var scheduler_task = scheduler.RunUntilDone(); scheduler_task.Wait(); Assert.That(receipt.Completed); if (receipt.EscapedExceptionInfo != null) { receipt.EscapedExceptionInfo.Throw(); } Assert.That(scheduler.TickCount, Is.EqualTo(expectedIterations)); }
protected async Task <FrameContext> runProgram(string program, Dictionary <string, object> variablesIn, List <ISpecFinder> moduleSpecFinders, int expectedIterations, bool checkExceptions = true) { // TODO: This dependency association is kind of gross. It's almost circular and is broken by assigning // the interpreter reference to the schedular after its initial constructor. var scheduler = new Scheduler(); var interpreter = new Interpreter(scheduler); interpreter.DumpState = true; foreach (var finder in moduleSpecFinders) { interpreter.AddModuleFinder(finder); } scheduler.SetInterpreter(interpreter); scheduler.OnTaskScheduled += whenTaskScheduled; escapedExceptions = new List <ExceptionDispatchInfo>(); CodeObject compiledProgram = null; Task <CodeObject> compiledTask = null; try { // This is awaitable now but relies on the scheduler. We'll tick the scheduler // awhile until this resolves. compiledTask = ByteCodeCompiler.Compile(program, variablesIn, scheduler); } catch (CloacaParseException parseFailed) { Assert.Fail(parseFailed.Message); } for (int tries = 1; tries < 1000 && !compiledTask.IsCompleted && escapedExceptions.Count == 0; ++tries) { await scheduler.Tick(); } if (!compiledTask.IsCompleted) { Assert.Fail("Compilation did not finish with interpreter after 1,000 scheduler ticks"); } else if (escapedExceptions.Count > 0) { escapedExceptions[0].Throw(); } compiledProgram = await compiledTask; Dis.dis(compiledProgram); receipt = scheduler.Schedule(compiledProgram); FrameContext context = receipt.Frame; foreach (string varName in variablesIn.Keys) { context.SetVariable(varName, variablesIn[varName]); } // Waiting on the task makes sure we get punched in the face by any exceptions it throws. // But they'll come rolling in as AggregateExceptions so we'll have to unpack them. var scheduler_task = scheduler.RunUntilDone(); scheduler_task.Wait(); Assert.That(receipt.Completed); if (checkExceptions) { AssertNoExceptions(); } Assert.That(scheduler.TickCount, Is.EqualTo(expectedIterations)); return(context); }