Beispiel #1
0
        /// <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();
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        /// <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();
        }
Beispiel #4
0
        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);
        }
Beispiel #5
0
        /// <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);
        }
Beispiel #6
0
        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();
        }