/// <summary> /// Pass the script forward to be scheduled and run offline from the REPL. /// </summary> /// <param name="program">The code to run.</param> public void RunBackground(string program) { 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); if (errorListener.Errors.Count > 0) { var errorText = new StringBuilder("There were errors trying to compile the script. We cannot run it.\n"); foreach (var error in errorListener.Errors) { errorText.Append(error); errorText.Append("\n"); } throw new Exception(errorText.ToString()); } var antlrVisitorContext = parser.file_input(); var variablesIn = new Dictionary <string, object>(); var visitor = new CloacaBytecodeVisitor(variablesIn); visitor.Visit(antlrVisitorContext); CodeObject compiledProgram = visitor.RootProgram.Build(); var context = Scheduler.Schedule(compiledProgram); Scheduler.Tick(); }
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(); }
static CodeObject compileCode(string program, Dictionary <string, object> variablesIn) { 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 context = parser.file_input(); var visitor = new CloacaBytecodeVisitor(variablesIn); visitor.Visit(context); // 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(); return(compiledProgram); }
/// <summary> /// Build a Cloaca script from source to produce a CodeObject that you can run from the scheduler. /// </summary> /// <param name="program">The script text.</param> /// <param name="variablesIn">Variables referenced from the script that have to be externally injected. The /// dictionary maps the string key as the variable name and the value is the object to be referenced in the script.</param> /// <returns>The compiled code.</returns> /// <exception cref="CloacaParseException">There were errors trying to build the script into byte code.</exception> public static CodeObject Compile(string program, Dictionary <string, object> variablesIn) { 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(); errorListener.AssertNoErrors(); var visitor = new CloacaBytecodeVisitor(variablesIn); visitor.Visit(antlrVisitorContext); CodeObject compiledProgram = visitor.RootProgram.Build(); return(compiledProgram); }
static void Main(string[] cmdline_args) { if (cmdline_args.Length != 1) { Console.WriteLine("One argument required: path to script to compile and run."); return; } string program = null; using (var inFile = new StreamReader(cmdline_args[0])) { program = inFile.ReadToEnd(); } 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); if (errorListener.Errors.Count > 0) { Console.WriteLine("There were errors trying to compile the script. We cannot run it."); return; } var antlrVisitorContext = parser.file_input(); var variablesIn = new Dictionary <string, object>(); var visitor = new CloacaBytecodeVisitor(variablesIn); visitor.Visit(antlrVisitorContext); CodeObject compiledProgram = visitor.RootProgram.Build(); var scheduler = new Scheduler(); var interpreter = new Interpreter(scheduler); interpreter.DumpState = true; scheduler.SetInterpreter(interpreter); var context = scheduler.Schedule(compiledProgram).Frame; foreach (string varName in variablesIn.Keys) { context.SetVariable(varName, variablesIn[varName]); } interpreter.StepMode = true; bool traceMode = false; var debugRepl = new Piksel.LibREPL.Repl("dbg> ") { HeaderTitle = "Cloaca Interpreter Debugger", HeaderSubTitle = "Debug Cloaca ByteCode Evaluation" }; debugRepl.Commands.Add("g", new Command() { Action = (repl, cmd, args) => { if (scheduler.Done) { repl.Write("Scheduled programs are all done."); } else { interpreter.StepMode = false; while (!scheduler.Done) { try { scheduler.Tick().Wait(); } catch (AggregateException wrappedEscapedException) { // Given the nature of exception handling, we should normally only have one of these! ExceptionDispatchInfo.Capture(wrappedEscapedException.InnerExceptions[0]).Throw(); } } } }, Description = "Runs until finished" }); debugRepl.Commands.Add("s", new Command() { Action = (repl, cmd, args) => { if (scheduler.Done) { repl.Write("Scheduled programs are all done."); } else { interpreter.StepMode = true; try { scheduler.Tick().Wait(); } catch (AggregateException wrappedEscapedException) { // Given the nature of exception handling, we should normally only have one of these! ExceptionDispatchInfo.Capture(wrappedEscapedException.InnerExceptions[0]).Throw(); } if (traceMode) { DumpState(scheduler); } } }, Description = "Steps one line of bytecode" }); debugRepl.Commands.Add("d", new Command() { Action = (repl, cmd, args) => { if (scheduler.Done) { repl.Write("Scheduled programs are all done."); } else { var currentTasklet = scheduler.LastTasklet; if (currentTasklet != null && currentTasklet.Cursor < currentTasklet.CodeBytes.Bytes.Length) { DumpDatastack(currentTasklet); } } }, Description = "Dumps the data stack" }); debugRepl.Commands.Add("t", new Command() { Action = (repl, cmd, args) => { traceMode = !traceMode; if (traceMode) { repl.Write("Trace mode on."); } else { repl.Write("Trace mode off."); } }, Description = "Toggle trace mode." }); debugRepl.Commands.Add("c", new Command() { Action = (repl, cmd, args) => { if (scheduler.Done) { repl.Write("Scheduled programs are all done."); } else { DumpCode(scheduler); } }, Description = "Disassembles the current code object." }); debugRepl.Commands.Add("l", new Command() { Action = (repl, cmd, args) => { if (scheduler.Done) { repl.Write("Scheduled programs are all done."); } else { var currentTasklet = scheduler.LastTasklet; if (currentTasklet != null && currentTasklet.Cursor < currentTasklet.CodeBytes.Bytes.Length) { if (args.Length == 0) { repl.Write(Dis.dis(currentTasklet.Program, currentTasklet.Cursor, 1)); } else if (args.Length == 1) { int count = Int32.Parse(args[0]); repl.Write(Dis.dis(currentTasklet.Program, currentTasklet.Cursor, count)); } } } }, Description = "Disassembles byte code based on the current location (not implemented yet)." }); debugRepl.Start(); }