Пример #1
0
        /// <summary>Adds a method that was found into this classes set of methods to compile.</summary>
        /// <param name="fragment">The first fragment of the method, used for generating errors. This gives a valid line number.</param>
        /// <param name="body">The block of code for this method.</param>
        /// <param name="name">The name of the method. Null if anonymous is true.</param>
        /// <param name="anonymous">True if this method is an anonymous one and requires a name.</param>
        /// <param name="parameters">The set of parameters for this method.</param>
        /// <param name="returnType">The type that this method returns.</param>
        /// <param name="isPublic">True if this is a public method; false for private.</param>
        /// <returns>The first fragment following the method, if there is one.</returns>
        protected virtual CodeFragment AddFoundMethod(CodeFragment fragment, CodeFragment body, string name, bool anonymous, BracketFragment parameters, TypeFragment returnType, bool isPublic)
        {
            if (body == null)
            {
                fragment.Error("Invalid function definition (" + name + "). The content block {} is missing or isnt valid.");
            }

            if (anonymous)
            {
                name = "Compiler-Generated-$" + AnonymousCount;
                AnonymousCount++;
            }

            // The following is the explicit code block for this function:
            BracketFragment codeBlock = (BracketFragment)body;
            CompiledMethod  cMethod   = new CompiledMethod(this, name, parameters, codeBlock, returnType, isPublic);
            MethodOverloads set       = MakeOrFind(name, cMethod.Builder.ReturnType);
            CodeFragment    next      = body.NextChild;

            if (anonymous)
            {
                CodeFragment newChild = DynamicMethodCompiler.Compile(cMethod, name, set.ReturnType, new ThisOperation(cMethod));
                newChild.AddAfter(body);
            }

            body.Remove();
            set.AddMethod(cMethod);
            FindMethods(codeBlock);

            return(next);
        }
Пример #2
0
        public override void OutputIL(NitroIL into)
        {
            if (!OutputTarget(into))
            {
                return;
            }

            if (Field != null)
            {
                if (Field.IsLiteral)
                {
                    // Special case - this field isn't actually a field at all!
                    // Load it's literal value:
                    object literalFieldValue = Field.GetValue(null);

                    // Get ready to write out the literal value:
                    CompiledFragment literalValue = new CompiledFragment(literalFieldValue);

                    // It might even be from an enum - let's check:
                    if (Field.FieldType.IsEnum)
                    {
                        // Ok great it's from an enum. What type is it?
                        Type literalValueType = Enum.GetUnderlyingType(Field.FieldType);

                        // Use that type to emit the value:
                        literalValue.EmitValue(literalValueType, into);
                    }
                    else
                    {
                        literalValue.OutputIL(into);
                    }
                }
                else if (ParentFragment != null && ParentFragment.IsMemberAccessor() && Field.FieldType.IsValueType)
                {
                    // Are we followed by another PropertyOperation?
                    // A following operation in this sitation ends up being the parent.
                    // If we are, and we output a valuetype, Ldflda must be used.

                    if (IsStatic)
                    {
                        into.Emit(OpCodes.Ldsflda, Field);
                    }
                    else
                    {
                        into.Emit(OpCodes.Ldflda, Field);
                    }
                }
                else if (IsStatic)
                {
                    into.Emit(OpCodes.Ldsfld, Field);
                }
                else
                {
                    into.Emit(OpCodes.Ldfld, Field);
                }
            }
            else if (Property != null)
            {
                bool useVirtual = !IsStatic && !Property.PropertyType.IsValueType;

                into.Emit(useVirtual?OpCodes.Callvirt:OpCodes.Call, Property.GetGetMethod());
            }
            else if (Methods != null)
            {
                // Extension property (hopefully!). Look for a get method lookalike.

                // Get types:
                Type[] argTypes = new Type[] { OfType() };

                // Get the overload:
                MethodInfo getMethod = Types.GetOverload(Methods, argTypes);

                if (getMethod == null)
                {
                    Error(Name + " is a 'write only' extension property.");
                }

                // Call the set method:
                into.Emit(OpCodes.Call, getMethod);
            }
            else
            {
                DynamicMethodCompiler.Compile(Method, Name, MethodReturnType, Of).OutputIL(into);
            }
        }
Пример #3
0
        public override Type OutputType(out CompiledFragment v)
        {
            v = this;

            Type type = OfType();

            // Map to functionality:
            CompiledClass Class     = null;
            bool          isDynamic = Types.IsDynamic(type);

            // (Constant) binding flags:
            BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;

            if (Name == "length" && type.IsGenericType && !isDynamic)
            {
                // Does length actually exist as a field/ property?

                Field = type.GetField(Name, flags);

                if (Field == null)
                {
                    Property = type.GetProperty(Name, flags);

                    if (Property == null)
                    {
                        // Assume we meant count instead:
                        Name = "Count";
                    }
                }
            }

            if (isDynamic)
            {
                Class = Method.Script.GetClass(type);
            }
            else if (!Method.Script.AllowUse(type))
            {
                Error("Unable to access properties of type " + type + " as it has not been made accessible.");
            }

            if (isDynamic)
            {
                Field = Class.GetField(Name);
            }
            else
            {
                Field = type.GetField(Name, flags);
            }

            if (Field != null)
            {
                if (IsStatic && !Field.IsStatic)
                {
                    Error("Property " + Name + " is not static. You must use an object reference to access it.");
                }

                return(Field.FieldType);
            }

            if (isDynamic)
            {
                Property = Class.GetProperty(Name);
            }
            else
            {
                Property = type.GetProperty(Name, flags);
            }

            if (Property != null)
            {
                if (IsStatic)
                {
                    MethodInfo staticTest = Property.GetGetMethod();
                    if (staticTest == null)
                    {
                        staticTest = Property.GetSetMethod();
                    }
                    if (!staticTest.IsStatic)
                    {
                        Error("Property " + Name + " is not static. You must use an object reference to access it.");
                    }
                }
                return(Property.PropertyType);
            }

            if (isDynamic)
            {
                MethodReturnType = Class.MethodReturnType(Name);
            }
            else
            {
                MethodReturnType = Types.MethodReturnType(type, Name);
            }

            if (MethodReturnType != null)
            {
                if (Types.IsVoid(MethodReturnType))
                {
                    MethodReturnType = typeof(Void);
                }
                return(DynamicMethodCompiler.TypeFor(MethodReturnType));
            }

            if (Of.GetType() == typeof(ThisOperation))
            {
                // This was the first property - it can potentially be a static type name too.
                Type staticType = Method.Script.GetType(Name);
                if (staticType != null)
                {
                    // It's a static type! Generate a new type operation to replace this one and return the type.
                    v = new TypeOperation(Method, staticType);
                    return(v.OutputType(out v));
                }
            }

            if (Name == "this")
            {
                // This is handled here as it allows variables called "This". Use case: PowerUI.
                v = new ThisOperation(Method);
                return(v.OutputType(out v));
            }

            // Does it support indexing? If so, Do Parent["property"] instead.

            MethodOperation mOp = null;

            if (Input0 != null)
            {
                // This is a set. Input0 is the object we're setting.

                Type setType = Input0.OutputType(out Input0);

                // Get the set method:
                MethodInfo mInfo;

                if (isDynamic)
                {
                    mInfo = Class.FindMethodOverload("set_Item", new Type[] { typeof(string), setType });
                }
                else
                {
                    // Grab all the methods of the type:
                    MethodInfo[] allMethods = type.GetMethods();
                    mInfo = Types.GetOverload(allMethods, "set_Item", new Type[] { typeof(string), setType });
                }

                if (mInfo == null)
                {
                    // Try finding the extension method:
                    mInfo = FindExtensionMethod(type, "set");

                    if (mInfo == null)
                    {
                        // It doesn't exist!
                        // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+".");

                        // Create as a global:
                        Field = Method.Script.MainClass.DefineField(Name, true, setType);

                        return(setType);
                    }

                    // Extension property or method.
                    // -> We only know which based on MethodOperation later calling GetOverload.
                    //    Or OutputSet/ OutputIL being called.

                    return(mInfo.ReturnType);
                }

                // It exists - create the method operation now.
                mOp          = new MethodOperation(Method, mInfo, new CompiledFragment(Name), Input0);
                v            = mOp;
                mOp.CalledOn = Of;
                return(setType);
            }
            else
            {
                // Get.

                // Get the get method:
                MethodInfo mInfo;

                if (isDynamic)
                {
                    mInfo = Class.FindMethodOverload("get_Item", new Type[] { typeof(string) });
                }
                else
                {
                    // Grab all the methods of the type:
                    MethodInfo[] allMethods = type.GetMethods();
                    mInfo = Types.GetOverload(allMethods, "get_Item", new Type[] { typeof(string) });
                }


                if (mInfo == null)
                {
                    // Try finding the extension method:
                    mInfo = FindExtensionMethod(type, "get");

                    if (mInfo == null)
                    {
                        // It doesn't exist!
                        // Error("Property '"+ToString()+"' is not a property or extension of "+type.ToString()+".");

                        // Create as a global:
                        Field = Method.Script.MainClass.DefineField(Name, true, typeof(object));

                        return(typeof(object));
                    }

                    // Extension property or method.
                    // -> We only know which based on MethodOperation later calling GetOverload.
                    //    Or OutputSet/ OutputIL being called.

                    return(mInfo.ReturnType);
                }

                // It exists - create the method operation now:
                mOp          = new MethodOperation(Method, mInfo, new CompiledFragment(Name));
                v            = mOp;
                mOp.CalledOn = Of;
                return(mInfo.ReturnType);
            }
        }