Beispiel #1
0
        public static AstExpression Create(Source src, params string[] qualifier)
        {
            AstExpression @base = new AstSymbol(src, AstSymbolType.Global);

            foreach (var id in qualifier)
            {
                @base = new AstMember(@base,
                                      new AstIdentifier(src, id));
            }
            return(@base);
        }
Beispiel #2
0
        public Expression CompileNewExpression(AstNew e)
        {
            // Implicitly typed arrays
            if (e.OptionalType == null)
            {
                if (e.OptionalArguments != null)
                {
                    return(Error(e.Source, ErrorCode.E2001, "Array constructors cannot have argument list"));
                }
                if (e.OptionalArraySize != null)
                {
                    return(Error(e.Source, ErrorCode.E2002, "Cannot specify size on implicitly typed arrays"));
                }
                if (e.OptionalCollectionInitializer == null || e.OptionalCollectionInitializer.Count == 0)
                {
                    return(Error(e.Source, ErrorCode.E2003, "Must provide non-empty initializer list for implicitly typed arrays"));
                }

                var values = new Expression[e.OptionalCollectionInitializer.Count];
                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = CompileExpression(e.OptionalCollectionInitializer[i]);
                }

                var et = TryGetImplicitElementType(values);

                if (et == null)
                {
                    return(Error(e.Source, ErrorCode.E2004, "No best type found for implicitly typed array"));
                }

                for (int i = 0; i < values.Length; i++)
                {
                    values[i] = CompileImplicitCast(e.Source, et, values[i]);
                }

                return(et.IsValueType || et.IsReferenceType
                        ? new NewArray(e.Source, TypeBuilder.GetArray(et), values) :
                       et != DataType.Invalid
                        ? Error(e.Source, ErrorCode.E2080, "Cannot create an implicitly typed array of type " + et.Quote())
                        : Expression.Invalid);
            }

            var dt = NameResolver.GetType(Namescope, e.OptionalType);

            switch (dt.TypeType)
            {
            case TypeType.RefArray:
            {
                if (e.OptionalArguments != null)
                {
                    return(Error(e.Source, ErrorCode.E2005, "Array constructors cannot have argument list"));
                }

                var        at   = dt as RefArrayType;
                Expression size = null;

                if (e.OptionalArraySize != null)
                {
                    size = CompileImplicitCast(e.Source, Essentials.Int, CompileExpression(e.OptionalArraySize));
                    if (size.IsInvalid)
                    {
                        return(Expression.Invalid);
                    }
                }

                if (e.OptionalCollectionInitializer != null)
                {
                    var values = new Expression[e.OptionalCollectionInitializer.Count];
                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = CompileExpression(e.OptionalCollectionInitializer[i]);
                    }

                    if (size != null)
                    {
                        var c = Compiler.ConstantFolder.TryMakeConstant(size);
                        if (c == null || !c.Value.Equals(values.Length))
                        {
                            return(Error(size.Source, ErrorCode.E2006, "Inconsistent array size and initializer list length"));
                        }
                    }

                    switch (at.ElementType.BuiltinType)
                    {
                    case BuiltinType.Bool:
                    case BuiltinType.Byte:
                    case BuiltinType.Char:
                    case BuiltinType.Double:
                    case BuiltinType.Int:
                    case BuiltinType.Float:
                    case BuiltinType.Long:
                    case BuiltinType.SByte:
                    case BuiltinType.Short:
                    case BuiltinType.UInt:
                    case BuiltinType.ULong:
                    case BuiltinType.UShort:
                        // Disable warning on primitive types
                        break;

                    default:
                        if (TryGetImplicitElementType(values) == at.ElementType)
                        {
                            Log.Warning3(e.Source, ErrorCode.W2007, "Array can be instantiated as implicitly typed array (new[] { ... })");
                        }

                        break;
                    }

                    for (int i = 0; i < values.Length; i++)
                    {
                        values[i] = CompileImplicitCast(values[i].Source, at.ElementType, values[i]);
                    }

                    return(new NewArray(e.Source, at, values));
                }

                return(new NewArray(e.Source, at, size));
            }

            case TypeType.Class:
            case TypeType.Struct:
            case TypeType.GenericParameter:
            {
                if (dt.IsStatic)
                {
                    return(Error(e.Source, ErrorCode.E2090, "Cannot instantiate static class"));
                }

                if (e.OptionalArguments != null || e.OptionalCollectionInitializer != null)
                {
                    if (e.OptionalArraySize != null)
                    {
                        return(Error(e.Source, ErrorCode.E2008, "Object constructors cannot have array size"));
                    }

                    Expression newObject;

                    if (dt.IsStruct && (e.OptionalArguments == null || e.OptionalArguments.Count == 0))
                    {
                        newObject = new Default(e.Source, dt);
                    }
                    else
                    {
                        dt.PopulateMembers();

                        Constructor  ctor;
                        Expression[] args;

                        if (!TryResolveConstructorOverload(e.Source, dt.Constructors, e.OptionalArguments ?? AstArgument.Empty, out ctor, out args))
                        {
                            return(e.OptionalArguments != null && e.OptionalArguments.Count > 0
                                    ? (dt.Constructors.Count == 1
                                        ? Error(e.Source, ErrorCode.E2009, "Call to " + (dt + PrintableParameterList(dt.Constructors[0].Parameters)).Quote() + " has some invalid arguments " +
                                                PrintableArgumentList(e.OptionalArguments))
                                        : Error(e.Source, ErrorCode.E2009, dt.Quote() + " has no constructors matching the argument list " +
                                                PrintableArgumentList(e.OptionalArguments) +
                                                NameResolver.SuggestCandidates(dt.Constructors)))
                                    : Error(e.Source, ErrorCode.E0000, dt.Quote() + " has no default constructor"));
                        }

                        newObject = new NewObject(e.Source, ctor, args);
                    }

                    if (e.OptionalCollectionInitializer != null && e.OptionalCollectionInitializer.Count > 0)
                    {
                        var var = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("collection"), newObject.ReturnType);
                        CurrentVariableScope.Variables.Add(var.Name, var);

                        Expression root = new StoreLocal(e.Source, var, newObject);

                        // See if it is a member initializer or collection initializer
                        var containsAssignOp = false;

                        foreach (var i in e.OptionalCollectionInitializer)
                        {
                            if (i is AstBinary && (i as AstBinary).IsAssign)
                            {
                                containsAssignOp = true;
                                break;
                            }
                        }

                        if (containsAssignOp)
                        {
                            var initedMembers = new List <string>();

                            // Assign members
                            foreach (var i in e.OptionalCollectionInitializer)
                            {
                                var binOp = i as AstBinary;
                                if (binOp == null || binOp.Type != AstBinaryType.Assign || !(binOp.Left is AstIdentifier))
                                {
                                    Log.Error(i.Source, ErrorCode.E2077, "Invalid initalizer member declarator");
                                    continue;
                                }

                                var id     = (AstIdentifier)binOp.Left;
                                var member = new AstMember(new AstIdentifier(i.Source, var.Name), id);

                                if (binOp.Right is AstArrayInitializer)
                                {
                                    var ai         = binOp.Right as AstArrayInitializer;
                                    var collection = CompileExpression(member);

                                    var cvar = new Variable(e.Source, Function, Namescope.GetUniqueIdentifier("array"), collection.ReturnType);
                                    CurrentVariableScope.Variables.Add(cvar.Name, cvar);

                                    root = new SequenceOp(root, new StoreLocal(collection.Source, cvar, collection));

                                    if (collection.IsInvalid)
                                    {
                                        continue;
                                    }

                                    foreach (var ci in ai.Values)
                                    {
                                        root = new SequenceOp(root, CompileAddToCollection(cvar.Name, ci));
                                    }
                                }
                                else
                                {
                                    var assign = CompileAssign(new AstBinary(AstBinaryType.Assign, member, i.Source, binOp.Right));
                                    root = new SequenceOp(root, assign);

                                    if (assign.IsInvalid)
                                    {
                                        continue;
                                    }
                                }

                                foreach (var m in initedMembers)
                                {
                                    if (m == id.Symbol)
                                    {
                                        Log.Error(i.Source, ErrorCode.E2078, "Duplicate initialization of member " + id.Symbol.Quote());
                                        break;
                                    }
                                }

                                initedMembers.Add(id.Symbol);
                            }
                        }
                        else
                        {
                            // Add to collection
                            foreach (var i in e.OptionalCollectionInitializer)
                            {
                                root = new SequenceOp(root, CompileAddToCollection(var.Name, i));
                            }
                        }

                        return(new SequenceOp(root, new LoadLocal(e.Source, var)));
                    }

                    if (e.OptionalType is AstBuiltinType && dt.IsStruct)
                    {
                        Log.Warning(e.Source, ErrorCode.W0000, "Redundant 'new' operator on builtin struct initialization");
                    }

                    return(newObject);
                }

                return(Error(e.Source, ErrorCode.E2011, "Must provide argument list for object constructor"));
            }

            case TypeType.Delegate:
            {
                if (e.OptionalArguments == null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Must provide argument list for delegate constructor"));
                }

                var args = CompileArgumentList(e.OptionalArguments);

                if (e.OptionalCollectionInitializer != null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have collection initializer"));
                }
                if (e.OptionalArraySize != null)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction cannot have array size"));
                }
                if (args.Length != 1 || args[0].ExpressionType != ExpressionType.MethodGroup)
                {
                    return(Error(e.Source, ErrorCode.E0000, "Delegate construction requires one method argument"));
                }

                return(CompileImplicitCast(e.Source, dt, args[0]));
            }

            case TypeType.Invalid:
                return(Expression.Invalid);

            default:
                return(Error(e.Source, ErrorCode.E2012, "Instances of type " + dt.Quote() + " cannot be created using 'new' because it is not a class, struct or array type"));
            }
        }
Beispiel #3
0
 public void WriteMember(AstMember a)
 {
     Write(a.Base);
     WriteIdentifier(a.Name);
 }
        public PartialExpression ResolveMember(AstMember qualifier, int?typeParamCount)
        {
            var baseinfo = ResolveExpression(qualifier.Base, null);

            if (baseinfo.IsInvalid)
            {
                return(baseinfo);
            }

            switch (baseinfo.ExpressionType)
            {
            case PartialExpressionType.Value:
            case PartialExpressionType.Namespace:
            case PartialExpressionType.Type:
            case PartialExpressionType.Block:
                break;

            default:
                baseinfo = new PartialValue(CompilePartial(baseinfo));
                if (baseinfo.IsInvalid)
                {
                    return(baseinfo);
                }
                break;
            }

            switch (baseinfo.ExpressionType)
            {
            case PartialExpressionType.Value:
            {
                var ps    = baseinfo as PartialValue;
                var obj   = ps.Value.Address;
                var dt    = obj.ReturnType;
                var pinfo = TryResolveTypeMember(dt, qualifier.Name, typeParamCount, qualifier.Base, obj);
                if (pinfo != null)
                {
                    return(pinfo);
                }

                dt.PopulateMembers();

                // Check if it is a swizzle
                if (typeParamCount == null &&
                    dt.Swizzlers.Count > 0)
                {
                    var swizzle = qualifier.Name.Symbol;

                    // Match identfier with field name patterns
                    int  sp    = 0;
                    bool match = false;

                    List <Field>      fields = null;
                    List <Expression> args   = null;

                    while (true)
                    {
                        bool found = false;

                        foreach (var field in dt.Fields)
                        {
                            if (field.IsStatic || swizzle.IndexOf(field.UnoName, sp) != sp)
                            {
                                continue;
                            }

                            sp += field.UnoName.Length;

                            if (fields == null)
                            {
                                fields = new List <Field>();
                                args   = new List <Expression>();
                            }

                            fields.Add(field);
                            args.Add(new LoadField(qualifier.Source, obj, field));
                            found = true;
                            break;
                        }

                        if (found)
                        {
                            if (sp != swizzle.Length)
                            {
                                continue;
                            }

                            match = true;
                        }

                        break;
                    }

                    if (match)
                    {
                        var candidates = new List <Constructor>();

                        foreach (var swt in dt.Swizzlers)
                        {
                            swt.PopulateMembers();
                            candidates.AddRange(swt.Constructors);
                        }

                        var ctor = TryResolveConstructorOverload(qualifier.Name.Source, candidates, args.ToArray());
                        if (ctor == null)
                        {
                            Log.Error(qualifier.Name.Source, ErrorCode.E3103, "No matching method overload");
                            return(PartialExpression.Invalid);
                        }

                        Transforms.TryCreateReadonlyValueFieldIndirection(Namescope, ref obj);
                        return(new PartialValue(new Swizzle(qualifier.Source, ctor, obj, fields.ToArray())));
                    }
                }

                // Check if it is a member in an interface implemented by a generic parameter
                if (dt.IsGenericParameter)
                {
                    foreach (var it in dt.Interfaces)
                    {
                        pinfo = TryResolveTypeMember(it, qualifier.Name, typeParamCount, qualifier.Base, obj);
                        if (pinfo != null)
                        {
                            return(pinfo);
                        }
                    }
                }

                // Check if it is a static member in a type named <member.Base>
                if (qualifier.Base is AstIdentifier)
                {
                    var id = qualifier.Base as AstIdentifier;
                    pinfo = NameResolver.TryResolveMember(Namescope, id, null, null);

                    if (pinfo is PartialType)
                    {
                        pinfo = TryResolveTypeMember((pinfo as PartialType).Type, qualifier.Name, typeParamCount, id, null);
                        if (pinfo != null)
                        {
                            return(pinfo);
                        }
                    }
                }

                pinfo = TryResolveTypeExtension(obj, qualifier.Name, typeParamCount);
                if (pinfo != null)
                {
                    return(pinfo);
                }

                return(Compiler.Backend.AllowInvalidCode && Function.HasAttribute(Essentials.UxGeneratedAttribute)
                        ? PartialExpression.Invalid
                        : PartialError(qualifier.Source, ErrorCode.E3104, Compiler.GetTypeMemberNotFoundError(qualifier.Name, dt)));
            }

            case PartialExpressionType.Namespace:
            {
                var pn = baseinfo as PartialNamespace;
                return(NameResolver.TryResolveMember(pn.Namespace, qualifier.Name, typeParamCount, qualifier.Base) ??
                       PartialError(qualifier.Source, ErrorCode.E3105, Compiler.GetNamespaceMemberNotFoundError(qualifier.Name, pn.Namespace)));
            }

            case PartialExpressionType.Block:
            {
                var pdt = baseinfo as PartialBlock;
                return(NameResolver.TryResolveMember(pdt.Block, qualifier.Name, typeParamCount, qualifier.Base) ??
                       PartialError(qualifier.Source, ErrorCode.E3106, pdt.Block.Quote() + " does not contain a member named " + qualifier.Name.GetParameterizedSymbol(typeParamCount).Quote()));
            }

            case PartialExpressionType.Type:
            {
                var pdt = baseinfo as PartialType;
                return(TryResolveTypeMember(pdt.Type, qualifier.Name, typeParamCount, qualifier.Base, null) ??
                       PartialError(qualifier.Source, ErrorCode.E3107, Compiler.GetTypeMemberNotFoundError(qualifier.Name, pdt.Type)));
            }
            }

            throw new FatalException(qualifier.Source, ErrorCode.I0076, "Unhandled expression form: " + baseinfo.ExpressionType.ToString());
        }