예제 #1
0
파일: Machine.cs 프로젝트: rwaldron/magpie
        private Structure MakeCallFrame(int numLocals, Structure parentFrame, int instruction)
        {
            var frame = new Structure(numLocals + 2);
            frame[numLocals] = new Value(parentFrame);
            frame[numLocals + 1] = new Value(instruction);

            return frame;
        }
예제 #2
0
파일: Machine.cs 프로젝트: rwaldron/magpie
 private void Push(Structure value)
 {
     Push(new Value(value));
 }
예제 #3
0
파일: Machine.cs 프로젝트: rwaldron/magpie
        private void Call(int paramType, bool isTailCall)
        {
            // jump to the function
            int previousInstruction = mInstruction;

            mInstruction = PopInt();
            int numLocals = ReadInt();

            //### bob: work in progress stuff.
            if (mDebug != null)
            {
                string function = mDebug.GetFunctionName(mInstruction);
                //Console.WriteLine(">> calling " + function);
                //System.Diagnostics.Debug.WriteLine("calling " + function);
            }

            // if it's a tail call, discard the parent frame
            var parent = mCurrentFrame;
            if (isTailCall)
            {
                parent = mCurrentFrame[mCurrentFrame.Count - 2].Struct;
                previousInstruction = mCurrentFrame[mCurrentFrame.Count - 1].Int;
            }

            mCurrentFrame = MakeCallFrame(numLocals, parent, previousInstruction);

            // pop and store the argument
            if (paramType != 0) mCurrentFrame[0] = Pop();

            // track stack depth
            if (MaxStackDepth != 0)
            {
                int stackDepth = GetStackDepth(mCurrentFrame);

                if (stackDepth > MaxStackDepth) throw new MaxStackDepthExceededException(MaxStackDepth);
            }
        }
예제 #4
0
파일: Machine.cs 프로젝트: rwaldron/magpie
 private int GetStackDepth(Structure callFrame)
 {
     if (callFrame == null) return 0;
     return 1 + GetStackDepth(callFrame[callFrame.Count - 2].Struct);
 }
예제 #5
0
파일: Machine.cs 프로젝트: rwaldron/magpie
        public Value Interpret()
        {
            bool running = true;

            while (running)
            {
                OpCode theOp = ReadOpCode();
                //Console.WriteLine(theOp.ToString());

                switch (theOp)
                {
                    case OpCode.PushNull:       Push((Structure)null); break;
                    case OpCode.PushBool:       Push(ReadByte() != 0); break;
                    case OpCode.PushInt:        Push(ReadInt()); break;
                    case OpCode.PushString:     Push(mFile.ReadString(ReadInt())); break;

                    case OpCode.PushLocals:     Push(mCurrentFrame); break;

                    case OpCode.Alloc:
                        {
                            int slots = ReadInt();
                            Structure structure = new Structure(slots);

                            // initialize it
                            // note: slots are on stack in reverse order
                            // because they have been pushed in forward order.
                            // this ensures that arguments are evaluated left to right.
                            // for example: calling Foo (1, 2, 3) will create the arg
                            // tuple by evaluating 1, 2, 3 in order. this leaves the
                            // stack (from top down) looking like 3 2 1.
                            for (int i = slots - 1; i >= 0; i--)
                            {
                                structure[i] = Pop();
                            }

                            Push(structure);
                        }
                        break;

                    case OpCode.Load:
                        {
                            byte index = ReadByte();
                            Structure struc = PopStructure();
                            Value op = struc[index];

                            Push(op);
                        }
                        break;

                    case OpCode.Store:
                        {
                            byte index = ReadByte();
                            Structure struc = PopStructure();
                            struc[index] = Pop();
                        }
                        break;

                    case OpCode.LoadArray:
                        {
                            Structure struc = PopStructure();

                            int index = struc[0].Int;
                            Structure array = struc[1].Struct;

                            //### bob: should bounds-check

                            // add one to skip the first slot which holds the array size
                            Push(array[index + 1]);
                        }
                        break;

                    case OpCode.StoreArray:
                        {
                            Structure struc = PopStructure();
                            int index = struc[0].Int;
                            Structure array = struc[1].Struct;
                            Value value = struc[2];

                            //### bob: should bounds-check

                            // add one to skip the first slot which holds the array size
                            array[index + 1] = value;
                        }
                        break;

                    case OpCode.SizeArray:
                        {
                            Structure struc = PopStructure();

                            // array size is the first element
                            Push(struc[0]);
                        }
                        break;

                    case OpCode.Call0: Call(0, false); break;
                    case OpCode.Call1: Call(1, false); break;
                    case OpCode.CallN: Call(2, false); break;

                    case OpCode.TailCall0: Call(0, true); break;
                    case OpCode.TailCall1: Call(1, true); break;
                    case OpCode.TailCallN: Call(2, true); break;

                    case OpCode.ForeignCall0: ForeignCall(0); break;
                    case OpCode.ForeignCall1: ForeignCall(1); break;
                    case OpCode.ForeignCallN: ForeignCall(2); break;

                    case OpCode.Return:
                        {
                            mInstruction = mCurrentFrame[mCurrentFrame.Count - 1].Int;
                            mCurrentFrame = mCurrentFrame[mCurrentFrame.Count - 2].Struct;

                            // stop completely if we've returned from main
                            if (mCurrentFrame == null) running = false;
                        }
                        break;

                    case OpCode.Jump:               mInstruction = ReadInt(); break;
                    case OpCode.JumpIfFalse:        int offset = ReadInt();
                                                    if (!PopBool()) mInstruction = offset;
                                                    break;

                    case OpCode.BoolToString:       Push(PopBool() ? "true" : "false"); break;
                    case OpCode.IntToString:        Push(PopInt().ToString()); break;

                    case OpCode.EqualBool:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Bool == tuple[1].Bool);
                        }
                        break;

                    case OpCode.EqualInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int == tuple[1].Int);
                        }
                        break;

                    case OpCode.EqualString:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].String == tuple[1].String);
                        }
                        break;

                    case OpCode.LessInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int < tuple[1].Int);
                        }
                        break;

                    case OpCode.GreaterInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int > tuple[1].Int);
                        }
                        break;

                    case OpCode.NegateBool:         Push(!PopBool()); break;
                    case OpCode.NegateInt:          Push(-PopInt()); break;

                    case OpCode.AndBool:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Bool && tuple[1].Bool);
                        }
                        break;

                    case OpCode.OrBool:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Bool || tuple[1].Bool);
                        }
                        break;

                    case OpCode.AddInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int + tuple[1].Int);
                        }
                        break;

                    case OpCode.SubInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int - tuple[1].Int);
                        }
                        break;

                    case OpCode.MultInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int * tuple[1].Int);
                        }
                        break;

                    case OpCode.DivInt:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].Int / tuple[1].Int);
                        }
                        break;

                    case OpCode.Random:
                        {
                            // only create if needed
                            if (mRandom == null)
                            {
                                mRandom = new Random();
                            }

                            Push(mRandom.Next(PopInt()));
                        }
                        break;

                    case OpCode.AddString:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].String + tuple[1].String);
                        }
                        break;

                    case OpCode.Print:
                        string text = PopString();
                        if (Printed != null) Printed(this, new PrintEventArgs(text));
                        break;

                    case OpCode.StringCount:         Push(PopString().Length); break;

                    case OpCode.Substring:
                        {
                            Structure tuple = PopStructure();
                            Push(tuple[0].String.Substring(tuple[1].Int, tuple[2].Int));
                        }
                        break;

                    default: throw new Exception("Unknown opcode.");
                }
            }

            // if there is anything left on the stack, return it
            if (mOperands.Count > 0)
            {
                return mOperands.Peek();
            }

            return null;
        }
예제 #6
0
 public Value(Structure value) : this((object)value)
 {
 }
예제 #7
0
        public Value Interpret()
        {
            bool running = true;

            while (running)
            {
                OpCode theOp = ReadOpCode();
                //Console.WriteLine(theOp.ToString());

                switch (theOp)
                {
                case OpCode.PushNull:       Push((Structure)null); break;

                case OpCode.PushBool:       Push(ReadByte() != 0); break;

                case OpCode.PushInt:        Push(ReadInt()); break;

                case OpCode.PushString:     Push(mFile.ReadString(ReadInt())); break;

                case OpCode.PushLocals:     Push(mCurrentFrame); break;

                case OpCode.Alloc:
                {
                    int       slots     = ReadInt();
                    Structure structure = new Structure(slots);

                    // initialize it
                    // note: slots are on stack in reverse order
                    // because they have been pushed in forward order.
                    // this ensures that arguments are evaluated left to right.
                    // for example: calling Foo (1, 2, 3) will create the arg
                    // tuple by evaluating 1, 2, 3 in order. this leaves the
                    // stack (from top down) looking like 3 2 1.
                    for (int i = slots - 1; i >= 0; i--)
                    {
                        structure[i] = Pop();
                    }

                    Push(structure);
                }
                break;

                case OpCode.Load:
                {
                    byte      index = ReadByte();
                    Structure struc = PopStructure();
                    Value     op    = struc[index];

                    Push(op);
                }
                break;

                case OpCode.Store:
                {
                    byte      index = ReadByte();
                    Structure struc = PopStructure();
                    struc[index] = Pop();
                }
                break;

                case OpCode.LoadArray:
                {
                    Structure struc = PopStructure();

                    int       index = struc[0].Int;
                    Structure array = struc[1].Struct;

                    //### bob: should bounds-check

                    // add one to skip the first slot which holds the array size
                    Push(array[index + 1]);
                }
                break;

                case OpCode.StoreArray:
                {
                    Structure struc = PopStructure();
                    int       index = struc[0].Int;
                    Structure array = struc[1].Struct;
                    Value     value = struc[2];

                    //### bob: should bounds-check

                    // add one to skip the first slot which holds the array size
                    array[index + 1] = value;
                }
                break;

                case OpCode.SizeArray:
                {
                    Structure struc = PopStructure();

                    // array size is the first element
                    Push(struc[0]);
                }
                break;

                case OpCode.Call0: Call(0, false); break;

                case OpCode.Call1: Call(1, false); break;

                case OpCode.CallN: Call(2, false); break;

                case OpCode.TailCall0: Call(0, true); break;

                case OpCode.TailCall1: Call(1, true); break;

                case OpCode.TailCallN: Call(2, true); break;

                case OpCode.ForeignCall0: ForeignCall(0); break;

                case OpCode.ForeignCall1: ForeignCall(1); break;

                case OpCode.ForeignCallN: ForeignCall(2); break;

                case OpCode.Return:
                {
                    mInstruction  = mCurrentFrame[mCurrentFrame.Count - 1].Int;
                    mCurrentFrame = mCurrentFrame[mCurrentFrame.Count - 2].Struct;

                    // stop completely if we've returned from main
                    if (mCurrentFrame == null)
                    {
                        running = false;
                    }
                }
                break;

                case OpCode.Jump:               mInstruction = ReadInt(); break;

                case OpCode.JumpIfFalse:        int offset = ReadInt();
                    if (!PopBool())
                    {
                        mInstruction = offset;
                    }
                    break;

                case OpCode.BoolToString:       Push(PopBool() ? "true" : "false"); break;

                case OpCode.IntToString:        Push(PopInt().ToString()); break;

                case OpCode.EqualBool:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Bool == tuple[1].Bool);
                }
                break;

                case OpCode.EqualInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int == tuple[1].Int);
                }
                break;

                case OpCode.EqualString:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].String == tuple[1].String);
                }
                break;

                case OpCode.LessInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int < tuple[1].Int);
                }
                break;

                case OpCode.GreaterInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int > tuple[1].Int);
                }
                break;

                case OpCode.NegateBool:         Push(!PopBool()); break;

                case OpCode.NegateInt:          Push(-PopInt()); break;

                case OpCode.AndBool:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Bool && tuple[1].Bool);
                }
                break;

                case OpCode.OrBool:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Bool || tuple[1].Bool);
                }
                break;

                case OpCode.AddInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int + tuple[1].Int);
                }
                break;

                case OpCode.SubInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int - tuple[1].Int);
                }
                break;

                case OpCode.MultInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int * tuple[1].Int);
                }
                break;

                case OpCode.DivInt:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].Int / tuple[1].Int);
                }
                break;

                case OpCode.Random:
                {
                    // only create if needed
                    if (mRandom == null)
                    {
                        mRandom = new Random();
                    }

                    Push(mRandom.Next(PopInt()));
                }
                break;

                case OpCode.AddString:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].String + tuple[1].String);
                }
                break;

                case OpCode.Print:
                    string text = PopString();
                    if (Printed != null)
                    {
                        Printed(this, new PrintEventArgs(text));
                    }
                    break;

                case OpCode.StringCount:         Push(PopString().Length); break;

                case OpCode.Substring:
                {
                    Structure tuple = PopStructure();
                    Push(tuple[0].String.Substring(tuple[1].Int, tuple[2].Int));
                }
                break;

                default: throw new Exception("Unknown opcode.");
                }
            }

            // if there is anything left on the stack, return it
            if (mOperands.Count > 0)
            {
                return(mOperands.Peek());
            }

            return(null);
        }
예제 #8
0
 private void Push(Structure value)
 {
     Push(new Value(value));
 }
예제 #9
0
파일: Value.cs 프로젝트: rwaldron/magpie
 public Value(Structure value)
     : this((object)value)
 {
 }