Esempio n. 1
0
        private void TraceReferences()
        {
            while (_GrayList.Count > 0)
            {
                GearsObj obj = _GrayList.Dequeue();
#if DEBUG_LOG_GC
                Console.WriteLine($"Blacken {obj}");
#endif
                obj.Blacken(this);
            }
        }
Esempio n. 2
0
        public void MarkObject(GearsObj obj)
        {
            if (obj == null || obj.IsMarked)
            {
                return;
            }
#if DEBUG_LOG_GC
            Console.WriteLine($"Mark {obj}");
#endif
            _GrayList.Enqueue(obj);
            obj.IsMarked = true;
        }
Esempio n. 3
0
        private T GetObjectFromPtr <T>(GearsValue ptr) where T : GearsObj
        {
            if (!ptr.IsObjPtr)
            {
                throw new Exception($"GetObjectFromPtr: Value is not a pointer and cannot reference a {typeof(T).Name}.");
            }
            GearsObj obj = HeapGetObject(ptr.AsObjPtr);

            if (obj is T)
            {
                return(obj as T);
            }
            throw new Exception($"GetObjectFromPtr: Object is not {typeof(T).Name}.");
        }
Esempio n. 4
0
        // === Heap ==================================================================================================
        // ===========================================================================================================

        internal int HeapAddObject(GearsObj obj, bool allowGC = true)
        {
            for (int i = 0; i < _Heap.Length; i++)
            {
                if (_Heap[i] == null)
                {
                    _Heap[i] = obj;
#if DEBUG_LOG_GC
                    Console.WriteLine($"Allocate {obj.Type} at {i}");
#endif
                    return(i);
                }
            }
            if (allowGC)
            {
                CollectGarbage();
                int newIndex = HeapAddObject(obj, false);
                if (newIndex != -1)
                {
                    return(newIndex);
                }
            }
            throw new GearsRuntimeException(Chunk.LineAt(_IP), "Out of heap space.");
        }
Esempio n. 5
0
 public void SetField(Gears context, object wrappedObject, ulong name, GearsValue value)
 {
     if (_Fields.TryGetValue(name, out FieldInfo fieldInfo))
     {
         if (value.IsNumber)
         {
             if (!IsNumeric(fieldInfo.FieldType))
             {
                 throw new GearsRuntimeException($"Attempted to set {WrappedType.Name}.{fieldInfo.Name} to numeric value.");
             }
             try {
                 fieldInfo.SetValue(wrappedObject, Convert.ChangeType((double)value, fieldInfo.FieldType));
                 return;
             }
             catch (Exception e) {
                 throw new GearsRuntimeException($"Error setting {WrappedType.Name}.{fieldInfo.Name} to {(double)value}: {e.Message}");
             }
         }
         else if (value.IsNil && fieldInfo.FieldType == typeof(string))
         {
             fieldInfo.SetValue(wrappedObject, null);
             return;
         }
         else if (fieldInfo.FieldType == typeof(bool) && value.IsBool)
         {
             fieldInfo.SetValue(wrappedObject, value.IsTrue);
             return;
         }
         else if (value.IsObjPtr)
         {
             GearsObj obj = value.AsObject(context);
             if (fieldInfo.FieldType == typeof(string) && obj is GearsObjString objString)
             {
                 fieldInfo.SetValue(wrappedObject, objString.Value);
                 return;
             }
         }
     }
     else if (_Properties.TryGetValue(name, out PropertyInfo propertyInfo))
     {
         if (!propertyInfo.GetSetMethod().IsPublic)
         {
             throw new GearsRuntimeException($"Unsupported reference: Native class {WrappedType.Name} does not have a public set method for '{BitString.GetBitStr(name)}'.");
         }
         if (value.IsNumber)
         {
             if (!IsNumeric(propertyInfo.PropertyType))
             {
                 throw new GearsRuntimeException($"Attempted to set {WrappedType.Name}.{propertyInfo.Name} to numeric value.");
             }
             try {
                 propertyInfo.SetValue(wrappedObject, Convert.ChangeType((double)value, propertyInfo.PropertyType), null);
                 return;
             }
             catch (Exception e) {
                 throw new GearsRuntimeException($"Error setting {WrappedType.Name}.{propertyInfo.Name} to {(double)value}: {e.Message}");
             }
         }
         else if (value.IsNil && propertyInfo.PropertyType == typeof(string))
         {
             propertyInfo.SetValue(wrappedObject, null, null);
             return;
         }
         else if (propertyInfo.PropertyType == typeof(bool) && value.IsBool)
         {
             propertyInfo.SetValue(wrappedObject, value.IsTrue, null);
             return;
         }
         else if (value.IsObjPtr)
         {
             GearsObj obj = value.AsObject(context);
             if (propertyInfo.PropertyType == typeof(string) && obj is GearsObjString objString)
             {
                 propertyInfo.SetValue(wrappedObject, objString.Value, null);
                 return;
             }
         }
     }
     throw new GearsRuntimeException($"Unsupported native conversion: Error setting {WrappedType.Name}.{BitString.GetBitStr(name)} to {value}.");
 }
Esempio n. 6
0
        internal bool CallGearsFunction(ulong name, out object returned, params object[] args)
        {
            if (!Globals.TryGet(name, out GearsValue fnValue) || !fnValue.IsObjPtr)
            {
                // error: no function with that name.
                returned = $"Error: no function with name '{BitString.GetBitStr(name)}'.";
                return(false);
            }
            GearsObj fnObject = fnValue.AsObject(this);

            if (fnObject is GearsObjFunction fnFunction)
            {
                if (fnFunction.Arity != args.Length)
                {
                    // error: wrong arity.
                    returned = $"Error: called '{BitString.GetBitStr(name)}' with wrong arity (passed arity is '{args?.Length ?? 0}').";
                    return(false);
                }
            }
            Push(fnValue);
            for (int i = 0; i < (args?.Length ?? 0); i++)
            {
                object arg     = args[i];
                Type   argType = arg?.GetType() ?? null;
                if (arg == null)
                {
                    Push(GearsValue.NilValue);
                }
                else if (GearsNativeWrapper.IsNumeric(argType))
                {
                    double fieldValue = Convert.ToDouble(arg);
                    Push(new GearsValue(fieldValue));
                }
                else if (argType == typeof(bool))
                {
                    bool fieldValue = Convert.ToBoolean(arg);
                    Push(fieldValue ? GearsValue.TrueValue : GearsValue.FalseValue);
                }
                else if (argType == typeof(string))
                {
                    string fieldValue = Convert.ToString(arg);
                    if (fieldValue == null)
                    {
                        Push(GearsValue.NilValue);
                    }
                    else
                    {
                        Push(GearsValue.CreateObjPtr(HeapAddObject(new GearsObjString(fieldValue))));
                    }
                }
                else if (argType.IsSubclassOf(typeof(object)))
                {
                    if (arg == null)
                    {
                        Push(GearsValue.NilValue);
                    }
                    else
                    {
                        Push(GearsValue.CreateObjPtr(HeapAddObject(new GearsObjInstanceNative(this, arg))));
                    }
                }
                else
                {
                    // error: could not pass arg of this type
                    returned = $"Error: called '{BitString.GetBitStr(name)}' with argument of type '{argType.Name}' as parameter {i}. Gears could not interpret this argument.";
                    return(false);
                }
            }
            Call(args?.Length ?? 0);
            Run();
            returned = LastReturnValue; // the return value
            // todo: process return value?
            return(true);
        }
Esempio n. 7
0
        private void Call(int argCount)
        {
            GearsValue ptr = Peek(argCount);

            if (!ptr.IsObjPtr)
            {
                throw new GearsRuntimeException(Chunk.LineAt(_IP), "Attempted call to non-pointer.");
            }
            GearsObj obj = HeapGetObject(ptr.AsObjPtr);

            if (obj is GearsObjFunction function)
            {
                if (function.Arity != argCount)
                {
                    throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{function} expects {function.Arity} arguments but was passed {argCount}.");
                }
                int ip = function.IP;
                int bp = _SP - (function.Arity + 1);
                PushFrame(new GearsCallFrame(function, ip, bp));
            }
            else if (obj is GearsObjFunctionNative native)
            {
                if (native.Arity != argCount)
                {
                    throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{native} expects {native.Arity} arguments but was passed {argCount}.");
                }
                GearsValue[] args = new GearsValue[argCount];
                for (int i = argCount - 1; i >= 0; i--)
                {
                    args[i] = Pop();
                }
                Pop(); // pop the function signature
                Push(native.Invoke(args));
            }
            else if (obj is GearsObjBoundMethod method)
            {
                if (method.Method.Arity != argCount)
                {
                    throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{method} expects {method.Method.Arity} arguments but was passed {argCount}.");
                }
                int ip = method.Method.IP;
                int bp = _SP - (method.Method.Arity + 1);
                StackSet(bp, method.Receiver); // todo: this wipes out the method object. Is this bad?
                PushFrame(new GearsCallFrame(method.Method, ip, bp));
            }
            else if (obj is GearsObjClass classObj)
            {
                StackSet(_SP - argCount - 1, GearsValue.CreateObjPtr(HeapAddObject(new GearsObjInstanceLox(classObj))));
                if (classObj.Methods.TryGet(InitString, out GearsValue initPtr))
                {
                    if (!initPtr.IsObjPtr)
                    {
                        throw new GearsRuntimeException(Chunk.LineAt(_IP), "Attempted call to non-pointer.");
                    }
                    GearsObjFunction initFn = HeapGetObject(initPtr.AsObjPtr) as GearsObjFunction;
                    PushFrame(new GearsCallFrame(initFn, initFn.IP, _SP - argCount - 1));
                }
            }
            else
            {
                throw new GearsRuntimeException(Chunk.LineAt(_IP), $"Unhandled call to object {obj}");
            }
        }
Esempio n. 8
0
        // --- Can probably merge a ton of code from the three call methods ---

        private void CallInvoke()
        {
            int        argCount    = ReadByte();
            ulong      methodName  = (ulong)ReadConstant();
            GearsValue receiverPtr = Peek(argCount);

            if (!receiverPtr.IsObjPtr)
            {
                throw new GearsRuntimeException(Chunk.LineAt(_IP), "Attempted invoke to non-pointer.");
            }
            GearsObj obj = receiverPtr.AsObject(this);

            if (obj is GearsObjInstance instance)
            {
                if (instance.TryGetField(methodName, out GearsValue value))
                {
                    if (!value.IsObjPtr)
                    {
                        throw new GearsRuntimeException(Chunk.LineAt(_IP), "Attempted call to non-pointer.");
                    }
                    GearsObj objFn = HeapGetObject(value.AsObjPtr);
                    if (objFn is GearsObjFunction function)
                    {
                        if (function.Arity != argCount)
                        {
                            throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{function} expects {function.Arity} arguments but was passed {argCount}.");
                        }
                        int ip = function.IP;
                        int bp = _SP - (function.Arity + 1);
                        PushFrame(new GearsCallFrame(function, ip, bp));
                    }
                    else if (objFn is GearsObjFunctionNative native)
                    {
                        if (native.Arity != argCount)
                        {
                            throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{native} expects {native.Arity} arguments but was passed {argCount}.");
                        }
                        GearsValue[] args = new GearsValue[argCount];
                        for (int i = argCount - 1; i >= 0; i--)
                        {
                            args[i] = Pop();
                        }
                        Pop(); // pop the function signature
                        Push(native.Invoke(args));
                    }
                    else
                    {
                        throw new GearsRuntimeException(Chunk.LineAt(_IP), $"Could not resolve method {methodName} in {instance}.");
                    }
                }
                else if (instance is GearsObjInstanceLox instanceLox)
                {
                    InvokeFromClass(argCount, methodName, receiverPtr, instanceLox.Class);
                }
                else
                {
                    throw new GearsRuntimeException(Chunk.LineAt(_IP), $"{instance} does not have a public method named '{BitString.GetBitStr(methodName)}'.");
                }
                return;
            }
            throw new GearsRuntimeException(Chunk.LineAt(_IP), "Attempted invoke to non-instance.");
        }