상속: Wren.Core.Objects.Obj
예제 #1
0
        // The function that this closure is an instance of.

        // The upvalues this function has closed over.

        // Creates a new closure object that invokes [fn]. Allocates room for its
        // upvalues, but assumes outside code will populate it.
        public ObjClosure(ObjFn fn)
        {
            Function = fn;
            Upvalues = new ObjUpvalue[fn.NumUpvalues];
            Type = ObjType.Closure;
            ClassObj = WrenVM.FnClass;
        }
예제 #2
0
        public static string DumpByteCode(WrenVM vm, ObjFn fn)
        {
            string s = "";
            int ip = 0;
            byte[] bytecode = fn.Bytecode;
            while (ip < bytecode.Length)
            {
                Instruction instruction = (Instruction)bytecode[ip++];
                s += instruction + " ";
                switch (instruction)
                {
                    case Instruction.NULL:
                    case Instruction.FALSE:
                    case Instruction.TRUE:
                    case Instruction.POP:
                    case Instruction.DUP:
                    case Instruction.CLOSE_UPVALUE:
                    case Instruction.RETURN:
                    case Instruction.END:
                    case Instruction.LOAD_LOCAL_0:
                    case Instruction.LOAD_LOCAL_1:
                    case Instruction.LOAD_LOCAL_2:
                    case Instruction.LOAD_LOCAL_3:
                    case Instruction.LOAD_LOCAL_4:
                    case Instruction.LOAD_LOCAL_5:
                    case Instruction.LOAD_LOCAL_6:
                    case Instruction.LOAD_LOCAL_7:
                    case Instruction.LOAD_LOCAL_8:
                        s += ("\n");
                        break;

                    case Instruction.LOAD_LOCAL:
                    case Instruction.STORE_LOCAL:
                    case Instruction.LOAD_UPVALUE:
                    case Instruction.STORE_UPVALUE:
                    case Instruction.LOAD_FIELD_THIS:
                    case Instruction.STORE_FIELD_THIS:
                    case Instruction.LOAD_FIELD:
                    case Instruction.STORE_FIELD:
                    case Instruction.CLASS:
                        s += (bytecode[ip++] + "\n");
                        break;


                    case Instruction.CALL_0:
                    case Instruction.CALL_1:
                    case Instruction.CALL_2:
                    case Instruction.CALL_3:
                    case Instruction.CALL_4:
                    case Instruction.CALL_5:
                    case Instruction.CALL_6:
                    case Instruction.CALL_7:
                    case Instruction.CALL_8:
                    case Instruction.CALL_9:
                    case Instruction.CALL_10:
                    case Instruction.CALL_11:
                    case Instruction.CALL_12:
                    case Instruction.CALL_13:
                    case Instruction.CALL_14:
                    case Instruction.CALL_15:
                    case Instruction.CALL_16:
                        int method = (bytecode[ip] << 8) + bytecode[ip + 1];
                        s += vm.MethodNames[method] + "\n";
                        ip += 2;
                        break;
                    case Instruction.CONSTANT:
                    case Instruction.LOAD_MODULE_VAR:
                    case Instruction.STORE_MODULE_VAR:
                    case Instruction.JUMP:
                    case Instruction.LOOP:
                    case Instruction.JUMP_IF:
                    case Instruction.AND:
                    case Instruction.OR:
                    case Instruction.METHOD_INSTANCE:
                    case Instruction.METHOD_STATIC:
                    case Instruction.LOAD_MODULE:
                        int method1 = (bytecode[ip] << 8) + bytecode[ip + 1];
                        s += method1 + "\n";
                        ip += 2;
                        break;

                    case Instruction.SUPER_0:
                    case Instruction.SUPER_1:
                    case Instruction.SUPER_2:
                    case Instruction.SUPER_3:
                    case Instruction.SUPER_4:
                    case Instruction.SUPER_5:
                    case Instruction.SUPER_6:
                    case Instruction.SUPER_7:
                    case Instruction.SUPER_8:
                    case Instruction.SUPER_9:
                    case Instruction.SUPER_10:
                    case Instruction.SUPER_11:
                    case Instruction.SUPER_12:
                    case Instruction.SUPER_13:
                    case Instruction.SUPER_14:
                    case Instruction.SUPER_15:
                    case Instruction.SUPER_16:
                    case Instruction.IMPORT_VARIABLE:
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++]);
                        s += (" ");
                        s += (bytecode[ip++] + "\n");
                        break;

                    case Instruction.CLOSURE:
                        {
                            int constant = (bytecode[ip] << 8) | bytecode[ip + 1];
                            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;
        }
예제 #3
0
        public static void BindMethodCode(ObjClass classObj, ObjFn fn)
        {
            int ip = 0;
            for (; ; )
            {
                Instruction instruction = (Instruction)fn.Bytecode[ip++];
                switch (instruction)
                {
                    case Instruction.LOAD_FIELD:
                    case Instruction.STORE_FIELD:
                    case Instruction.LOAD_FIELD_THIS:
                    case Instruction.STORE_FIELD_THIS:
                        // 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.SUPER_0:
                    case Instruction.SUPER_1:
                    case Instruction.SUPER_2:
                    case Instruction.SUPER_3:
                    case Instruction.SUPER_4:
                    case Instruction.SUPER_5:
                    case Instruction.SUPER_6:
                    case Instruction.SUPER_7:
                    case Instruction.SUPER_8:
                    case Instruction.SUPER_9:
                    case Instruction.SUPER_10:
                    case Instruction.SUPER_11:
                    case Instruction.SUPER_12:
                    case Instruction.SUPER_13:
                    case Instruction.SUPER_14:
                    case Instruction.SUPER_15:
                    case Instruction.SUPER_16:
                        {
                            // 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;
                }
            }
        }
예제 #4
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(string debugName)
        {
            // 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(),
                                        new ObjString(_parser.SourcePath),
                                        debugName,
                                        _debugSourceLines);

            // 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.EmitShortArg(Instruction.CONSTANT, 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;
        }
예제 #5
0
 // Creates a new closure object that invokes [fn]. Allocates room for its
 // upvalues, but assumes outside code will populate it.
 public ObjClosure(ObjFn fn)
 {
     Function = fn;
     Upvalues = new ObjUpvalue[fn.NumUpvalues];
     ClassObj = WrenVM.FnClass;
 }