Beispiel #1
0
        public static void BindMethodCode(ObjClass classObj, ObjFn fn)
        {
            int ip = 0;
            for (; ; )
            {
                Instruction instruction = (Instruction)fn.Bytecode[ip++];
                switch (instruction)
                {
                    case Instruction.LoadField:
                    case Instruction.StoreField:
                    case Instruction.LoadFieldThis:
                    case Instruction.StoreFieldThis:
                        // Shift this class's fields down past the inherited ones. We don't
                        // check for overflow here because we'll see if the number of fields
                        // overflows when the subclass is created.
                        fn.Bytecode[ip++] += (byte)classObj.Superclass.NumFields;
                        break;

                    case Instruction.Super0:
                    case Instruction.Super1:
                    case Instruction.Super2:
                    case Instruction.Super3:
                    case Instruction.Super4:
                    case Instruction.Super5:
                    case Instruction.Super6:
                    case Instruction.Super7:
                    case Instruction.Super8:
                    case Instruction.Super9:
                    case Instruction.Super10:
                    case Instruction.Super11:
                    case Instruction.Super12:
                    case Instruction.Super13:
                    case Instruction.Super14:
                    case Instruction.Super15:
                    case Instruction.Super16:
                        {
                            // Skip over the symbol.
                            ip += 2;

                            // Fill in the constant slot with a reference to the superclass.
                            int constant = (fn.Bytecode[ip] << 8) | fn.Bytecode[ip + 1];
                            fn.Constants[constant] = classObj.Superclass;
                            break;
                        }

                    case Instruction.Closure:
                        {
                            // Bind the nested closure too.
                            int constant = (fn.Bytecode[ip] << 8) | fn.Bytecode[ip + 1];
                            BindMethodCode(classObj, fn.Constants[constant] as ObjFn);

                            ip += GetNumArguments(fn.Bytecode, new List<Obj>(fn.Constants), ip - 1);
                            break;
                        }

                    case Instruction.End:
                        return;

                    default:
                        // Other instructions are unaffected, so just skip over them.
                        ip += GetNumArguments(fn.Bytecode, new List<Obj>(fn.Constants), ip - 1);
                        break;
                }
            }
        }
Beispiel #2
0
        public static string DumpByteCode(SophieVM vm, ObjFn fn)
        {
            string s = "";
            int ip = 0;
            byte[] bytecode = fn.Bytecode;
            while (ip < bytecode.Length)
            {
                s += ip + ": ";
                Instruction instruction = (Instruction)bytecode[ip++];
                s += (instruction + " ");
                switch (instruction)
                {
                    case Instruction.Null:
                    case Instruction.False:
                    case Instruction.True:
                    case Instruction.Zero:
                    case Instruction.One:
                    case Instruction.Pop:
                    case Instruction.Dup:
                    case Instruction.CloseUpvalue:
                    case Instruction.Return:
                    case Instruction.End:
                    case Instruction.LoadLocal0:
                    case Instruction.LoadLocal1:
                    case Instruction.LoadLocal2:
                    case Instruction.LoadLocal3:
                    case Instruction.LoadLocal4:
                    case Instruction.LoadLocal5:
                    case Instruction.LoadLocal6:
                    case Instruction.LoadLocal7:
                    case Instruction.LoadLocal8:
                        s += ("\n");
                        break;

                    case Instruction.LoadLocal:
                    case Instruction.StoreLocal:
                    case Instruction.LoadUpvalue:
                    case Instruction.StoreUpvalue:
                    case Instruction.LoadFieldThis:
                    case Instruction.StoreFieldThis:
                    case Instruction.LoadField:
                    case Instruction.StoreField:
                    case Instruction.Class:
                    case Instruction.SmallConstant:
                        s += (bytecode[ip++] + "\n");
                        break;

                    case Instruction.Call0:
                    case Instruction.Call1:
                    case Instruction.Call2:
                    case Instruction.Call3:
                    case Instruction.Call4:
                    case Instruction.Call5:
                    case Instruction.Call6:
                    case Instruction.Call7:
                    case Instruction.Call8:
                    case Instruction.Call9:
                    case Instruction.Call10:
                    case Instruction.Call11:
                    case Instruction.Call12:
                    case Instruction.Call13:
                    case Instruction.Call14:
                    case Instruction.Call15:
                    case Instruction.Call16:
                        int method = (bytecode[ip] << 8) + bytecode[ip + 1];
                        s += vm.MethodNames[method] + "\n";
                        ip += 2;
                        break;
                    case Instruction.Constant:
                    case Instruction.LoadModuleVar:
                    case Instruction.StoreModuleVar:
                    case Instruction.Jump:
                    case Instruction.Loop:
                    case Instruction.JumpIf:
                    case Instruction.And:
                    case Instruction.Or:
                    case Instruction.MethodInstance:
                    case Instruction.MethodStatic:
                    case Instruction.LoadModule:
                        int method1 = (bytecode[ip] << 8) + bytecode[ip + 1];
                        s += method1 + "\n";
                        ip += 2;
                        break;

                    case Instruction.Super0:
                    case Instruction.Super1:
                    case Instruction.Super2:
                    case Instruction.Super3:
                    case Instruction.Super4:
                    case Instruction.Super5:
                    case Instruction.Super6:
                    case Instruction.Super7:
                    case Instruction.Super8:
                    case Instruction.Super9:
                    case Instruction.Super10:
                    case Instruction.Super11:
                    case Instruction.Super12:
                    case Instruction.Super13:
                    case Instruction.Super14:
                    case Instruction.Super15:
                    case Instruction.Super16:
                    case Instruction.ImportVariable:
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++] + "\n");
                        break;

                    case Instruction.Closure:
                        {
                            int constant = (bytecode[ip + 1] << 8) | bytecode[ip + 2];
                            ObjFn loadedFn = (ObjFn)fn.Constants[constant];

                            // There are two bytes for the constant, then two for each upvalue.
                            int j = 2 + (loadedFn.NumUpvalues * 2);
                            while (j > 0)
                            {
                                s += (bytecode[ip++]);
                                s += (" ");
                                j--;
                            }
                            s += "\n";
                        }
                        break;
                }
            }
            return s;
        }
Beispiel #3
0
        // Finishes [compiler], which is compiling a function, method, or chunk of top
        // level code. If there is a parent compiler, then this emits code in the
        // parent compiler to load the resulting function.
        private ObjFn EndCompiler()
        {
            // If we hit an error, don't bother creating the function since it's borked
            // anyway.
            if (_parser.HasError)
            {
                _parser.Vm.Compiler = _parent;
                return null;
            }

            // Mark the end of the bytecode. Since it may contain multiple early returns,
            // we can't rely on Instruction.RETURN to tell us we're at the end.
            Emit(Instruction.End);

            // Create a function object for the code we just compiled.
            ObjFn fn = new ObjFn(_parser.Module,
                                        _constants.ToArray(),
                                        _numUpValues,
                                        _numParams,
                                        _bytecode.ToArray());

            // In the function that contains this one, load the resulting function object.
            if (_parent != null)
            {
                int constant = _parent.AddConstant(fn);

                // If the function has no upvalues, we don't need to create a closure.
                // We can just load and run the function directly.
                if (_numUpValues == 0)
                {
                    _parent.EmitConstant(constant);
                }
                else
                {
                    // Capture the upvalues in the new closure object.
                    _parent.EmitShortArg(Instruction.Closure, constant);

                    // Emit arguments for each upvalue to know whether to capture a local or
                    // an upvalue.
                    // TODO: Do something more efficient here?
                    for (int i = 0; i < _numUpValues; i++)
                    {
                        _parent.Emit(_upvalues[i].IsLocal ? 1 : 0);
                        _parent.Emit(_upvalues[i].Index);
                    }
                }
            }

            // Pop this compiler off the stack.
            _parser.Vm.Compiler = _parent;

            return fn;
        }