示例#1
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, IfStatement ifStatement)
        {
            bcc.CompileExpression(parser, buffer, ifStatement.Condition, true);
            ByteBuffer trueCode = new ByteBuffer();

            bcc.Compile(parser, trueCode, ifStatement.TrueCode);
            ByteBuffer falseCode = new ByteBuffer();

            bcc.Compile(parser, falseCode, ifStatement.FalseCode);

            if (falseCode.Size == 0)
            {
                if (trueCode.Size == 0)
                {
                    buffer.Add(ifStatement.Condition.FirstToken, OpCode.POP);
                }
                else
                {
                    buffer.Add(ifStatement.Condition.FirstToken, OpCode.JUMP_IF_FALSE, trueCode.Size);
                    buffer.Concat(trueCode);
                }
            }
            else
            {
                trueCode.Add(null, OpCode.JUMP, falseCode.Size);
                buffer.Add(ifStatement.Condition.FirstToken, OpCode.JUMP_IF_FALSE, trueCode.Size);
                buffer.Concat(trueCode);
                buffer.Concat(falseCode);
            }
        }
示例#2
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ForEachLoop forEachLoop)
        {
            bcc.CompileExpression(parser, buffer, forEachLoop.IterationExpression, true);
            buffer.Add(
                forEachLoop.IterationExpression.FirstToken,
                OpCode.VERIFY_TYPE_IS_ITERABLE,
                forEachLoop.ListLocalId.ID,
                forEachLoop.IndexLocalId.ID);

            ByteBuffer body  = new ByteBuffer();
            ByteBuffer body2 = new ByteBuffer();

            bcc.Compile(parser, body2, forEachLoop.Code);

            body.Add(
                forEachLoop.FirstToken,
                OpCode.ITERATION_STEP,
                body2.Size + 1,
                forEachLoop.IterationVariableId.ID,
                forEachLoop.IndexLocalId.ID,
                forEachLoop.ListLocalId.ID);

            body2.Add(null, OpCode.JUMP, -body2.Size - 2);
            body.Concat(body2);

            body.ResolveBreaks();
            body.ResolveContinues();

            buffer.Concat(body);
        }
示例#3
0
        public async void Execute(string program, Dictionary <string, object> variablesIn)
        {
            CodeObject compiledProgram = null;

            try
            {
                compiledProgram = ByteCodeCompiler.Compile(program, variablesIn);
            }
            catch (Exception ex)
            {
                WriteStdout(ex.Message);
                return;
            }
            var receipt = _scheduler.Schedule(compiledProgram);

            foreach (var variableName in variablesIn.Keys)
            {
                receipt.Frame.SetVariable(variableName, variablesIn[variableName]);
            }

            while (!_scheduler.Done)
            {
                await _scheduler.Tick();
            }

            if (receipt.Completed)
            {
                if (receipt.EscapedExceptionInfo != null)
                {
                    WriteStdout($"{receipt.EscapedExceptionInfo.SourceException}");
                }
                WriteStdout("Done.");
            }
        }
示例#4
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ForLoop forLoop)
        {
            bcc.Compile(parser, buffer, forLoop.Init);

            ByteBuffer codeBuffer = new ByteBuffer();

            bcc.Compile(parser, codeBuffer, forLoop.Code);
            codeBuffer.ResolveContinues(true); // resolve continues as jump-to-end before you add the step instructions.
            bcc.Compile(parser, codeBuffer, forLoop.Step);

            ByteBuffer forBuffer = new ByteBuffer();

            bcc.CompileExpression(parser, forBuffer, forLoop.Condition, true);
            forBuffer.Add(forLoop.Condition.FirstToken, OpCode.JUMP_IF_FALSE, codeBuffer.Size + 1); // +1 to go past the jump I'm about to add.

            forBuffer.Concat(codeBuffer);
            forBuffer.Add(null, OpCode.JUMP, -forBuffer.Size - 1);

            forBuffer.ResolveBreaks();

            buffer.Concat(forBuffer);
        }
示例#5
0
        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));
        }
示例#6
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, DoWhileLoop doWhileLoop)
        {
            ByteBuffer loopBody = new ByteBuffer();

            bcc.Compile(parser, loopBody, doWhileLoop.Code);
            loopBody.ResolveContinues(true); // continues should jump to the condition, hence the true.

            ByteBuffer condition = new ByteBuffer();

            bcc.CompileExpression(parser, condition, doWhileLoop.Condition, true);
            loopBody.Concat(condition);
            loopBody.Add(doWhileLoop.Condition.FirstToken, OpCode.JUMP_IF_TRUE, -loopBody.Size - 1);
            loopBody.ResolveBreaks();

            buffer.Concat(loopBody);
        }
示例#7
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, WhileLoop whileLoop)
        {
            ByteBuffer loopBody = new ByteBuffer();

            bcc.Compile(parser, loopBody, whileLoop.Code);
            ByteBuffer condition = new ByteBuffer();

            bcc.CompileExpression(parser, condition, whileLoop.Condition, true);

            condition.Add(whileLoop.Condition.FirstToken, OpCode.JUMP_IF_FALSE, loopBody.Size + 1);
            condition.Concat(loopBody);
            condition.Add(null, OpCode.JUMP, -condition.Size - 1);

            condition.ResolveBreaks();
            condition.ResolveContinues();

            buffer.Concat(condition);
        }
示例#8
0
        public static void Compile(
            ByteCodeCompiler bcc,
            ParserContext parser,
            ByteBuffer buffer,
            FunctionDefinition funDef,
            bool isMethod)
        {
            ByteBuffer tBuffer = new ByteBuffer();

            List <int> offsetsForOptionalArgs = new List <int>();

            CompileFunctionArgs(bcc, parser, tBuffer, funDef.ArgNames, funDef.DefaultValues, offsetsForOptionalArgs, funDef.Locals);

            if (funDef.CompilationScope.IsStaticallyTyped)
            {
                EncodeArgTypeCheck(tBuffer, funDef, funDef.ResolvedArgTypes);
            }

            bcc.Compile(parser, tBuffer, funDef.Code);

            List <int> args = new List <int>()
            {
                funDef.FunctionID,
                parser.GetId(funDef.NameToken.Value),                // local var to save in
                GetMinArgCountFromDefaultValuesList(funDef.DefaultValues),
                funDef.ArgNames.Length,                              // max number of args supplied
                isMethod ? (funDef.Modifiers.HasStatic ? 2 : 1) : 0, // type (0 - function, 1 - method, 2 - static method)
                isMethod ? ((ClassDefinition)funDef.Owner).ClassID : 0,
                funDef.LocalScopeSize,
                tBuffer.Size,
                offsetsForOptionalArgs.Count
            };

            args.AddRange(offsetsForOptionalArgs);

            buffer.Add(
                funDef.FirstToken,
                OpCode.FUNCTION_DEFINITION,
                funDef.NameToken.Value,
                args.ToArray());

            buffer.Concat(tBuffer);
            AddDebugSymbolData(buffer, parser, funDef);
        }
示例#9
0
        public async Task <object> Load(IInterpreter interpreter, FrameContext context, PyModuleSpec spec)
        {
            var foundPath  = (string)spec.LoaderState;
            var inFile     = File.ReadAllText(foundPath);
            var moduleCode = ByteCodeCompiler.Compile(inFile, new Dictionary <string, object>());
            await interpreter.CallInto(context, moduleCode, new object[0]);

            if (context.EscapedDotNetException != null)
            {
                throw context.EscapedDotNetException;
            }

            var moduleFrame = context.callStack.Pop();
            var module      = PyModule.Create(spec.Name);

            for (int local_i = 0; local_i < moduleFrame.LocalNames.Count; ++local_i)
            {
                module.__setattr__(moduleFrame.LocalNames[local_i], moduleFrame.Locals[local_i]);
            }

            return(module);
        }
示例#10
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, Lambda lambda, bool outputUsed)
        {
            ByteCodeCompiler.EnsureUsed(lambda, outputUsed);

            ByteBuffer tBuffer = new ByteBuffer();

            List <int> offsetsForOptionalArgs = new List <int>();

            Expression[] argDefaultValues_allRequired = new Expression[lambda.Args.Length];
            FunctionDefinitionEncoder.CompileFunctionArgs(bcc, parser, tBuffer, lambda.Args, argDefaultValues_allRequired, offsetsForOptionalArgs, lambda.ArgVarIds);

            bcc.Compile(parser, tBuffer, lambda.Code);

            List <int> args = new List <int>()
            {
                lambda.Args.Length, // min number of args required
                lambda.Args.Length, // max number of args supplied
                lambda.LocalScopeSize,
                tBuffer.Size,
                offsetsForOptionalArgs.Count
            };

            args.AddRange(offsetsForOptionalArgs);

            VariableId[] closureIds = lambda.ClosureIds;
            args.Add(closureIds.Length);
            foreach (VariableId closureVarId in closureIds)
            {
                args.Add(closureVarId.ClosureID);
            }

            buffer.Add(
                lambda.FirstToken,
                OpCode.LAMBDA,
                args.ToArray());

            buffer.Concat(tBuffer);
        }
示例#11
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, ConstructorDefinition constructor, ByteBuffer complexFieldInitializers)
        {
            ByteBuffer tBuffer = new ByteBuffer();

            ClassDefinition cd = (ClassDefinition)constructor.Owner;

            List <int> offsetsForOptionalArgs = new List <int>();

            FunctionDefinitionEncoder.CompileFunctionArgs(bcc, parser, tBuffer, constructor.ArgNames, constructor.DefaultValues, offsetsForOptionalArgs, constructor.ArgLocalIds);

            int minArgs = 0;
            int maxArgs = constructor.ArgNames.Length;

            for (int i = 0; i < constructor.ArgNames.Length; ++i)
            {
                if (constructor.DefaultValues[i] == null)
                {
                    minArgs++;
                }
                else
                {
                    break;
                }
            }

            if (constructor.BaseToken != null)
            {
                bcc.CompileExpressionList(parser, tBuffer, constructor.BaseArgs, true);
                tBuffer.Add(
                    constructor.BaseToken,
                    OpCode.CALL_FUNCTION,
                    (int)FunctionInvocationType.BASE_CONSTRUCTOR,
                    constructor.BaseArgs.Length,
                    cd.BaseClass.Constructor.FunctionID,
                    0,
                    cd.BaseClass.ClassID);
            }

            if (complexFieldInitializers != null)
            {
                tBuffer.Concat(complexFieldInitializers);
            }

            bcc.Compile(parser, tBuffer, constructor.Code);
            tBuffer.Add(null, OpCode.RETURN, 0);

            List <int> args = new List <int>()
            {
                constructor.FunctionID,
                -1,
                minArgs,
                maxArgs,
                constructor.Modifiers.HasStatic ? 4 : 3,
                cd.ClassID,
                constructor.LocalScopeSize,
                tBuffer.Size,
                offsetsForOptionalArgs.Count,
            };

            args.AddRange(offsetsForOptionalArgs);

            buffer.Add(constructor.FirstToken, OpCode.FUNCTION_DEFINITION, "<constructor>", args.ToArray());
            buffer.Concat(tBuffer);
        }
示例#12
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, SwitchStatement switchStatement)
        {
            bool isInt = switchStatement.UsesIntegers;

            bcc.CompileExpression(parser, buffer, switchStatement.Condition, true);

            ByteBuffer chunkBuffer = new ByteBuffer();

            Dictionary <int, int>    chunkIdsToOffsets  = new Dictionary <int, int>();
            Dictionary <int, int>    integersToChunkIds = new Dictionary <int, int>();
            Dictionary <string, int> stringsToChunkIds  = new Dictionary <string, int>();

            int defaultChunkId = -1;

            foreach (SwitchStatement.Chunk chunk in switchStatement.Chunks)
            {
                int chunkId = chunk.ID;

                if (chunk.Cases.Length == 1 && chunk.Cases[0] == null)
                {
                    defaultChunkId = chunkId;
                }
                else
                {
                    foreach (Expression expression in chunk.Cases)
                    {
                        if (isInt)
                        {
                            integersToChunkIds[((IntegerConstant)expression).Value] = chunkId;
                        }
                        else
                        {
                            stringsToChunkIds[((StringConstant)expression).Value] = chunkId;
                        }
                    }
                }

                chunkIdsToOffsets[chunkId] = chunkBuffer.Size;

                bcc.Compile(parser, chunkBuffer, chunk.Code);
            }

            chunkBuffer.ResolveBreaks();

            int defaultOffsetLength = defaultChunkId == -1
                ? chunkBuffer.Size
                : chunkIdsToOffsets[defaultChunkId];

            List <int> args = new List <int>()
            {
                defaultOffsetLength
            };

            if (isInt)
            {
                foreach (int caseValue in integersToChunkIds.Keys.OrderBy(_ => _))
                {
                    int chunkId = integersToChunkIds[caseValue];
                    int offset  = chunkIdsToOffsets[chunkId];
                    args.Add(caseValue);
                    args.Add(offset);
                }
            }
            else
            {
                foreach (string caseValue in stringsToChunkIds.Keys.OrderBy(_ => _))
                {
                    int chunkId = stringsToChunkIds[caseValue];
                    int offset  = chunkIdsToOffsets[chunkId];
                    args.Add(parser.GetStringConstant(caseValue));
                    args.Add(offset);
                }
            }

            buffer.Add(
                switchStatement.FirstToken,
                isInt ? OpCode.SWITCH_INT : OpCode.SWITCH_STRING,
                args.ToArray());

            buffer.Concat(chunkBuffer);
        }
示例#13
0
        public static void Compile(ByteCodeCompiler bcc, ParserContext parser, ByteBuffer buffer, TryStatement tryStatement)
        {
            ByteBuffer tryCode = new ByteBuffer();

            bcc.Compile(parser, tryCode, tryStatement.TryBlock);

            if (tryStatement.TryBlock.Length > 0 && tryStatement.TryBlock[0] is TryStatement)
            {
                // If the try block begins with another try block, that'll mess with the EsfToken metadata
                // which is declared at the beginning of the try block's PC and is singular.
                // Get around this limitation by tacking on a noop (JUMP +0) in this reasonably rare edge case.
                tryCode.AddFrontSlow(null, OpCode.JUMP, 0);
            }

            List <ByteBuffer> catchBlocks = new List <ByteBuffer>();

            for (int i = 0; i < tryStatement.CatchBlocks.Length; ++i)
            {
                TryStatement.CatchBlock catchBlock = tryStatement.CatchBlocks[i];
                ByteBuffer catchBlockBuffer        = new ByteBuffer();
                bcc.Compile(parser, catchBlockBuffer, catchBlock.Code);
                catchBlocks.Add(catchBlockBuffer);
            }

            ByteBuffer finallyCode = new ByteBuffer();

            bcc.Compile(parser, finallyCode, tryStatement.FinallyBlock);
            finallyCode.ResolveBreaksAndContinuesForFinally(false);
            finallyCode.Add(null, OpCode.FINALLY_END,
                            new int[] {
                // First 2 args are the same as a BREAK op code
                // Last 2 args are the same as a CONTINUE op code
                // These are all 0 and are resolved into their final values in the same pass as BREAK and CONTINUE
                0,    // break flag 0|1|2
                0,    // break offset
                0,    // continue flag 0|1|2
                0     // continue offset
            });


            // All user code is now compiled and offsets are sort of known.
            // Now build a lookup jump router thingy for all the catch blocks, if any.

            ByteBuffer allCatchBlocks = new ByteBuffer();

            if (catchBlocks.Count > 0)
            {
                /*
                 *  It'll look something like this...
                 *  0   EXCEPTION_HANDLED_TOGGLE true
                 *  1   JUMP_IF_EXCEPTION_IS_TYPE offset varId type1, type2, ...
                 *  2   JUMP_IF_EXCEPTION_IS_TYPE offset varId type3
                 *  3   EXCEPTION_HANDLED_TOGGLE false
                 *  4   JUMP [to finally]
                 *
                 *  5   catch block 1
                 *      ...
                 *  22  last line in catch block 1
                 *  23  JUMP [to finally]
                 *
                 *  24  catch block 2...
                 *      ...
                 *  72  last line in catch block 2
                 *
                 *  73  finally code begins...
                 */

                // Add jumps to the end of each catch block to jump to the end.
                // Going in reverse order is easier for this.
                int totalSize = 0;
                for (int i = catchBlocks.Count - 1; i >= 0; --i)
                {
                    ByteBuffer catchBlockBuffer = catchBlocks[i];
                    if (totalSize > 0) // omit the last block since a JUMP 0 is pointless.
                    {
                        catchBlockBuffer.Add(null, OpCode.JUMP, totalSize);
                    }
                    totalSize += catchBlockBuffer.Size;
                }

                // Now generate the header. This is also done backwards since it's easier.
                ByteBuffer exceptionSortHeader = new ByteBuffer();

                int offset = 2                        // EXCEPTION_HANDLED_TOGGLE + final JUMP
                             + catchBlocks.Count - 1; // remaining jump instructions to jump over

                // Add all the JUMP_IF_EXCEPTION_OF_TYPE instructions.
                for (int i = 0; i < catchBlocks.Count; ++i)
                {
                    TryStatement.CatchBlock cb = tryStatement.CatchBlocks[i];
                    ByteBuffer cbByteBuffer    = catchBlocks[i];
                    int        variableId      = cb.VariableLocalScopeId.ID;

                    // for each catch block insert a type-check-jump
                    List <int> typeCheckArgs = new List <int>()
                    {
                        offset, variableId
                    };                                                                // first arg is offset, second is variable ID (or -1), successive args are all class ID's
                    typeCheckArgs.AddRange(cb.TypeClasses.Select <ClassDefinition, int>(cd => cd.ClassID));
                    exceptionSortHeader.Add(null, OpCode.JUMP_IF_EXCEPTION_OF_TYPE, typeCheckArgs.ToArray());

                    // add the block to the running total
                    offset += cbByteBuffer.Size;

                    // ...but subtract 1 for the JUMP_IF_EXCEPTION_OF_TYPE you just added.
                    offset -= 1;
                }
                exceptionSortHeader.Add(null, OpCode.EXCEPTION_HANDLED_TOGGLE, 0);
                exceptionSortHeader.Add(null, OpCode.JUMP, totalSize);

                allCatchBlocks.Add(null, OpCode.EXCEPTION_HANDLED_TOGGLE, 1);
                allCatchBlocks.Concat(exceptionSortHeader);
                foreach (ByteBuffer catchBlock in catchBlocks)
                {
                    allCatchBlocks.Concat(catchBlock);
                }
            }

            int tryBegin = buffer.Size;

            buffer.Concat(tryCode);
            buffer.Add(null, OpCode.JUMP, allCatchBlocks.Size);
            buffer.Concat(allCatchBlocks);
            buffer.ResolveBreaksAndContinuesForFinally(true);

            buffer.Concat(finallyCode);

            int offsetToCatch   = tryCode.Size + 1;
            int offsetToFinally = offsetToCatch + allCatchBlocks.Size;

            buffer.SetEsfToken(tryBegin, offsetToCatch, offsetToFinally);
        }
示例#14
0
        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);
        }