bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r)
        {
            // Bottom-level reached
            if (id.InnerDeclaration == null && Contains(id.IdHash) && !id.ModuleScoped)
            {
                // Associate template param with r
                return(Set((p != null && id.IdHash == p.NameHash) ? p : null, r, id.IdHash));
            }

            var deducee = DResolver.StripMemberSymbols(AbstractType.Get(r)) as DSymbol;

            if (id.InnerDeclaration != null && deducee != null && deducee.Definition.NameHash == id.IdHash)
            {
                var physicalParentType = TypeDeclarationResolver.HandleNodeMatch(deducee.Definition.Parent, ctxt, null, id.InnerDeclaration);
                if (HandleDecl(p, id.InnerDeclaration, physicalParentType))
                {
                    if (Contains(id.IdHash))
                    {
                        Set((p != null && id.IdHash == p.NameHash) ? p : null, deducee, id.IdHash);
                    }
                    return(true);
                }
            }

            /*
             * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r
             */
            var _r = TypeDeclarationResolver.ResolveSingle(id, ctxt);

            return(_r != null && (EnforceTypeEqualityWhenDeducing ?
                                  ResultComparer.IsEqual(r, _r) :
                                  ResultComparer.IsImplicitlyConvertible(r, _r)));
        }
        /// <summary>
        /// Returns false if the item has already been set before and if the already set item is not equal to 'r'.
        /// Inserts 'r' into the target dictionary and returns true otherwise.
        /// </summary>
        bool Set(ITemplateParameter p, ISemantic r, string name = null)
        {
            if (string.IsNullOrEmpty(name))
            {
                name = p.Name;
            }

            TemplateParameterSymbol rl = null;

            if (!TargetDictionary.TryGetValue(name, out rl) || rl == null)
            {
                TargetDictionary[name] = new TemplateParameterSymbol(p, r, null, TargetDictionary.ParameterOwner);
                return(true);
            }
            else
            {
                if (rl != null)
                {
                    if (ResultComparer.IsEqual(rl.Base, r))
                    {
                        return(true);
                    }
                    else
                    {
                        // Error: Ambiguous assignment
                    }
                }

                TargetDictionary[name] = new TemplateParameterSymbol(p, r, null, TargetDictionary.ParameterOwner);

                return(false);
            }
        }
Beispiel #3
0
        /// <summary>
        /// Returns false if the item has already been set before and if the already set item is not equal to 'r'.
        /// Inserts 'r' into the target dictionary and returns true otherwise.
        /// </summary>
        bool Set(TemplateParameter p, ISemantic r, int nameHash)
        {
            if (p == null)
            {
                if (nameHash != 0 && TargetDictionary.ExpectedParameters != null)
                {
                    foreach (var tpar in TargetDictionary.ExpectedParameters)
                    {
                        if (tpar.NameHash == nameHash)
                        {
                            p = tpar;
                            break;
                        }
                    }
                }
            }

            if (p == null)
            {
                ctxt.LogError(null, "no fitting template parameter found!");
                return(false);
            }

            // void call(T)(T t) {}
            // call(myA) -- T is *not* myA but A, so only assign myA's type to T.
            if (p is TemplateTypeParameter)
            {
                var newR = Resolver.TypeResolution.DResolver.StripMemberSymbols(AbstractType.Get(r));
                if (newR != null)
                {
                    r = newR;
                }
            }

            TemplateParameterSymbol rl;

            if (!TargetDictionary.TryGetValue(p, out rl) || rl == null)
            {
                TargetDictionary[p] = new TemplateParameterSymbol(p, r);
                return(true);
            }
            else
            {
                if (ResultComparer.IsEqual(rl.Base, r))
                {
                    TargetDictionary[p] = new TemplateParameterSymbol(p, r);
                    return(true);
                }
                else if (rl == null)
                {
                    TargetDictionary[p] = new TemplateParameterSymbol(p, r);
                }

                // Error: Ambiguous assignment

                return(false);
            }
        }
        private bool evalIsExpression_NoAlias(IsExpression isExpression, AbstractType typeToCheck)
        {
            if (isExpression.TypeSpecialization != null)
            {
                var spec = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(isExpression.TypeSpecialization, ctxt));

                return(spec != null && spec.Length != 0 && (isExpression.EqualityTest ?
                                                            ResultComparer.IsEqual(typeToCheck, spec[0]) :
                                                            ResultComparer.IsImplicitlyConvertible(typeToCheck, spec[0], ctxt)));
            }

            return(isExpression.EqualityTest && evalIsExpression_EvalSpecToken(isExpression, typeToCheck, false).Item1);
        }
Beispiel #5
0
        bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r)
        {
            // Bottom-level reached
            if (id.InnerDeclaration == null && Contains(id.Id) && !id.ModuleScoped)
            {
                // Associate template param with r
                return(Set(p, r, id.Id));
            }

            /*
             * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r
             */
            var _r = TypeDeclarationResolver.Resolve(id, ctxt);

            ctxt.CheckForSingleResult(_r, id);

            return(_r != null && _r.Length != 0 &&
                   (EnforceTypeEqualityWhenDeducing ?
                    ResultComparer.IsEqual(r, _r[0]) :
                    ResultComparer.IsImplicitlyConvertible(r, _r[0])));
        }
        internal static bool TryHandleMethodArgumentTuple(ResolutionContext ctxt, ref bool add,
                                                          List <ISemantic> callArguments,
                                                          DMethod dm,
                                                          DeducedTypeDictionary deducedTypeDict, int currentParameter, ref int currentArg)
        {
            // .. so only check if it's an identifer & if the id represents a tuple parameter
            var id                 = dm.Parameters[currentParameter].Type as IdentifierDeclaration;
            var curNode            = dm as DNode;
            TemplateParameter tpar = null;

            while (curNode != null && !curNode.TryGetTemplateParameter(id.IdHash, out tpar))
            {
                curNode = curNode.Parent as DNode;
            }

            if (!(tpar is TemplateTupleParameter))
            {
                return(false);
            }

            int lastArgumentToTake = -1;

            /*
             * Note: an expression tuple parameter can occur also somewhere in between the parameter list!
             * void write(A...)(bool b, A a, double d) {}
             *
             * can be matched by
             * write(true, 1.2) as well as
             * write(true, "asdf", 1.2) as well as
             * write(true, 123, true, 'c', [3,4,5], 3.4) !
             */

            TemplateParameterSymbol tps;
            DTuple tuple = null;

            if (deducedTypeDict.TryGetValue(tpar, out tps) && tps != null)
            {
                if (tps.Base is DTuple)
                {
                    tuple = tps.Base as DTuple;
                    lastArgumentToTake = currentParameter + (tuple.Items == null ? 0 : (tuple.Items.Length - 1));
                }
                else
                {
                    // Error: Type param must be tuple!
                }
            }
            // - Get the (amount of) arguments that shall be put into the tuple
            else if (currentParameter == dm.Parameters.Count - 1)
            {
                // The usual case: A tuple of a variable length is put at the end of a parameter list..
                // take all arguments from i until the end of the argument list..
                // ; Also accept empty tuples
                lastArgumentToTake = callArguments.Count - 1;
            }
            else
            {
                // Get the type of the next expected parameter
                var nextExpectedParameter = DResolver.StripMemberSymbols(TypeDeclarationResolver.ResolveSingle(dm.Parameters[currentParameter + 1].Type, ctxt));

                // Look for the first argument whose type is equal to the next parameter's type..
                for (int k = currentArg; k < callArguments.Count; k++)
                {
                    if (ResultComparer.IsEqual(AbstractType.Get(callArguments[k]), nextExpectedParameter))
                    {
                        // .. and assume the tuple to go from i to the previous argument..
                        lastArgumentToTake = k - 1;
                        break;
                    }
                }
            }

            int argCountToHandle = lastArgumentToTake - currentArg + 1;

            if (tuple != null)
            {
                // - If there's been set an explicit type tuple, compare all arguments' types with those in the tuple
                if (tuple.Items != null)
                {
                    foreach (ISemantic item in tuple.Items)
                    {
                        if (currentArg >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[currentArg++], AbstractType.Get(item), ctxt))
                        {
                            add = false;
                            return(true);
                        }
                    }
                }
            }
            else
            {
                // - If there was no explicit initialization, put all arguments' types into a type tuple
                var argsToTake = new ISemantic[argCountToHandle];
                callArguments.CopyTo(currentArg, argsToTake, 0, argsToTake.Length);
                currentArg += argsToTake.Length;
                var tt = new DTuple(null, argsToTake);
                tps = new TemplateParameterSymbol(tpar, tt);

                //   and set the actual template tuple parameter deduction
                deducedTypeDict[tpar] = tps;
            }
            add = true;
            return(true);
        }
Beispiel #7
0
        public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol)
        {
            DSymbol ds = null;

            mightBeLegalUnresolvableSymbol = false;

            if (string.IsNullOrWhiteSpace(symName))
            {
                return(null);
            }

            // Try to handle a probably mangled string or C function.
            if (symName.StartsWith("_"))
            {
                try{
                    ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol;
                }catch {}
            }

            // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[])
            if (ds == null && Lexer.IsIdentifierPart((int)symName[0]))
            {
                mightBeLegalUnresolvableSymbol = true;
                ITypeDeclaration q;
                var method = DParser.ParseMethodDeclarationHeader(symName, out q);
                q           = Demangler.RemoveNestedTemplateRefsFromQualifier(q);
                method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type);
                var methodType       = TypeDeclarationResolver.GetMethodReturnType(method, ctxt);
                var methodParameters = new List <AbstractType>();

                if (method.Parameters != null && method.Parameters.Count != 0)
                {
                    foreach (var parm in method.Parameters)
                    {
                        methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt));
                    }
                }

                ctxt.ContextIndependentOptions |= ResolutionOptions.IgnoreAllProtectionAttributes;
                var overloads = TypeDeclarationResolver.Resolve(q, ctxt);


                if (overloads == null || overloads.Length == 0)
                {
                    return(null);
                }
                else if (overloads.Length == 1)
                {
                    ds = overloads[0] as DSymbol;
                }
                else
                {
                    foreach (var o in overloads)
                    {
                        ds = o as DSymbol;
                        if (ds == null || !(ds.Definition is DMethod))
                        {
                            continue;
                        }

                        var dm = ds.Definition as DMethod;
                        // Compare return types
                        if (dm.Type != null)
                        {
                            if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base))
                            {
                                continue;
                            }
                        }
                        else if (dm.Type == null && methodType != null)
                        {
                            return(null);
                        }

                        // Compare parameters
                        if (methodParameters.Count != dm.Parameters.Count)
                        {
                            continue;
                        }

                        for (int i = 0; i < methodParameters.Count; i++)
                        {
                            if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt)))
                            {
                                continue;
                            }
                        }
                    }
                }
            }

            if (ds != null)
            {
                return(ds.Definition);
            }
            return(null);
        }
        ISymbolValue EvalConcatenation(CatExpression x, ISymbolValue lValue)
        {
            // In the (not unusual) case that more than 2 arrays/strings shall be concat'ed - process them more efficiently
            var catQueue = new Queue <ISymbolValue>();

            var catEx = (x as CatExpression);

            catQueue.Enqueue(lValue);

            catEx = catEx.RightOperand as CatExpression;
            ISymbolValue r;

            while (catEx != null)
            {
                r = TryGetValue(E(catEx.LeftOperand));
                if (r == null)
                {
                    EvalError(catEx.LeftOperand, "Couldn't be evaluated.");
                    return(null);
                }
                catQueue.Enqueue(r);
                if (catEx.RightOperand is CatExpression)
                {
                    catEx = catEx.RightOperand as CatExpression;
                }
                else
                {
                    break;
                }
            }

            r = TryGetValue(E((catEx ?? x).RightOperand));
            if (r == null)
            {
                EvalError(catEx.LeftOperand, "Couldn't be evaluated.");
                return(null);
            }
            catQueue.Enqueue(r);

            // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array
            // myString ~ 'a' will append an 'a' to the string
            // 'a' ~ myString inserts 'a' at index 0

            // Determine whether we have to build up a string OR a normal list of atomic elements
            bool      isString      = true;
            ArrayType lastArrayType = null;

            foreach (var e in catQueue)
            {
                if (e is AssociativeArrayValue)
                {
                    EvalError(x, "Can't concatenate associative arrays", e);
                    return(null);
                }
                else if (e is ArrayValue)
                {
                    if (lastArrayType != null && !ResultComparer.IsEqual(lastArrayType, e.RepresentedType))
                    {
                        EvalError(x, "Both arrays must be of same type", new[] { lastArrayType, e.RepresentedType });
                        return(null);
                    }
                    lastArrayType = e.RepresentedType as ArrayType;

                    if ((e as ArrayValue).IsString)
                    {
                        continue;
                    }
                }
                else if (e is PrimitiveValue)
                {
                    var btt = (e as PrimitiveValue).BaseTypeToken;
                    if (btt == DTokens.Char || btt == DTokens.Dchar || btt == DTokens.Wchar)
                    {
                        continue;
                    }
                }

                isString = false;
            }

            if (lastArrayType == null)
            {
                EvalError(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", catQueue.ToArray());
                return(null);
            }

            if (isString)
            {
                var sb = new StringBuilder();

                while (catQueue.Count != 0)
                {
                    var e = catQueue.Dequeue();
                    if (e is ArrayValue)
                    {
                        sb.Append((e as ArrayValue).StringValue);
                    }
                    else if (e is PrimitiveValue)
                    {
                        sb.Append((char)((e as PrimitiveValue).Value));
                    }
                }
                return(new ArrayValue(GetStringType(LiteralSubformat.Utf8), sb.ToString()));
            }


            var elements = new List <ISymbolValue>();

            while (catQueue.Count != 0)
            {
                var e = catQueue.Dequeue();

                var av = e as ArrayValue;
                if (av != null)
                {
                    if (av.IsString)
                    {
                        elements.Add(av);
                    }
                    else if (av.Elements != null)
                    {
                        elements.AddRange(av.Elements);
                    }
                    continue;
                }

                if (!ResultComparer.IsImplicitlyConvertible(e.RepresentedType, lastArrayType.ValueType, ctxt))
                {
                    EvalError(x, "Element with type " + e.RepresentedType.ToCode() + " doesn't fit into array with type " + lastArrayType.ToCode(), catQueue.ToArray());
                    return(null);
                }

                elements.Add(e);
            }

            return(new ArrayValue(lastArrayType, elements.ToArray()));
        }
        /// <summary>
        /// Item1 - True, if isExpression returns true
        /// Item2 - If Item1 is true, it contains the type of the alias that is defined in the isExpression
        /// </summary>
        private Tuple <bool, AbstractType> evalIsExpression_EvalSpecToken(IsExpression isExpression, AbstractType typeToCheck, bool DoAliasHandling = false)
        {
            bool         r   = false;
            AbstractType res = null;

            switch (isExpression.TypeSpecializationToken)
            {
            /*
             * To handle semantic tokens like "return" or "super" it's just needed to
             * look into the current resolver context -
             * then, we'll be able to gather either the parent method or the currently scoped class definition.
             */
            case DTokens.Struct:
            case DTokens.Union:
            case DTokens.Class:
            case DTokens.Interface:
                if (r = typeToCheck is UserDefinedType &&
                        ((TemplateIntermediateType)typeToCheck).Definition.ClassType == isExpression.TypeSpecializationToken)
                {
                    res = typeToCheck;
                }
                break;

            case DTokens.Enum:
                if (!(typeToCheck is EnumType))
                {
                    break;
                }
                {
                    var tr = (UserDefinedType)typeToCheck;
                    r   = true;
                    res = tr.Base;
                }
                break;

            case DTokens.Function:
            case DTokens.Delegate:
                if (typeToCheck is DelegateType)
                {
                    var isFun = false;
                    var dgr   = (DelegateType)typeToCheck;
                    if (!dgr.IsFunctionLiteral)
                    {
                        r = isExpression.TypeSpecializationToken == (
                            (isFun = ((DelegateDeclaration)dgr.DeclarationOrExpressionBase).IsFunction) ? DTokens.Function : DTokens.Delegate);
                    }
                    // Must be a delegate otherwise
                    else
                    {
                        isFun = !(r = isExpression.TypeSpecializationToken == DTokens.Delegate);
                    }

                    if (r)
                    {
                        //TODO
                        if (isFun)
                        {
                            // TypeTuple of the function parameter types. For C- and D-style variadic functions, only the non-variadic parameters are included.
                            // For typesafe variadic functions, the ... is ignored.
                        }
                        else
                        {
                            // the function type of the delegate
                        }
                    }
                }
                else                         // Normal functions are also accepted as delegates
                {
                    r = isExpression.TypeSpecializationToken == DTokens.Delegate &&
                        typeToCheck is MemberSymbol &&
                        ((DSymbol)typeToCheck).Definition is DMethod;

                    //TODO: Alias handling, same as couple of lines above
                }
                break;

            case DTokens.Super:                     //TODO: Test this
                var dc = DResolver.SearchClassLikeAt(ctxt.ScopedBlock, isExpression.Location) as DClassLike;

                if (dc != null)
                {
                    var udt = DResolver.ResolveBaseClasses(new ClassType(dc, dc, null), ctxt, true) as ClassType;

                    if (r = udt.Base != null && ResultComparer.IsEqual(typeToCheck, udt.Base))
                    {
                        var l = new List <AbstractType>();
                        if (udt.Base != null)
                        {
                            l.Add(udt.Base);
                        }
                        if (udt.BaseInterfaces != null && udt.BaseInterfaces.Length != 0)
                        {
                            l.AddRange(udt.BaseInterfaces);
                        }

                        res = new DTuple(isExpression, l);
                    }
                }
                break;

            case DTokens.Const:
            case DTokens.Immutable:
            case DTokens.InOut:                     // TODO?
            case DTokens.Shared:
                if (r = typeToCheck.Modifier == isExpression.TypeSpecializationToken)
                {
                    res = typeToCheck;
                }
                break;

            case DTokens.Return:                     // TODO: Test
                IStatement _u = null;
                var        dm = DResolver.SearchBlockAt(ctxt.ScopedBlock, isExpression.Location, out _u) as DMethod;

                if (dm != null)
                {
                    var retType_ = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt);

                    if (r = retType_ != null && ResultComparer.IsEqual(typeToCheck, retType_))
                    {
                        res = retType_;
                    }
                }
                break;
            }

            return(new Tuple <bool, AbstractType>(r, res));
        }
        /// <summary>
        /// a + b; a - b; etc.
        /// </summary>
        ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null)
        {
            if (!eval)
            {
                return(lValue ?? E(x.LeftOperand));
            }

            var l = TryGetValue(lValue ?? E(x.LeftOperand));

            if (l == null)
            {
                /*
                 * In terms of adding opOverloading later on,
                 * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to
                 * search the type of l for methods called opAdd etc. and call that method via ctfe.
                 * Finally, return the value the opAdd method passed back - and everything is fine.
                 */

                /*
                 * Also, pointers should be implemented later on.
                 * http://dlang.org/expression.html#AddExpression
                 */

                throw new EvaluationException(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", lValue);
            }

            //TODO: Operator overloading

            // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c !
            if (x is MulExpression || x is PowExpression)
            {
                if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression))                 //TODO: This must be true only if it's a math expression, so not an assign expression etc.
                {
                    var sx = (OperatorBasedExpression)x.RightOperand;

                    // Now multiply/divide/mod expression 'l' with sx.LeftOperand
                    var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult);

                    // afterwards, evaluate the operation between the result just returned and the sx.RightOperand.
                    return(E(sx, intermediateResult));
                }

                return(HandleSingleMathOp(x, l, rValue ?? E(x.RightOperand), mult));
            }

            var r = TryGetValue(rValue ?? E(x.RightOperand));

            if (r == null)
            {
                throw new EvaluationException(x, "Right operand must evaluate to a value", lValue);
            }

            /*
             * TODO: Handle invalid values/value ranges.
             */

            if (x is XorExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) => {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value ^ (long)b.Value;
                }));
            }
            else if (x is OrExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value | (long)b.Value;
                }));
            }
            else if (x is AndExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    return (long)a.Value & (long)b.Value;
                }));
            }
            else if (x is ShiftExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b) =>
                {
                    EnsureIntegralType(a); EnsureIntegralType(b);
                    if (b.Value < 0 || b.Value > 31)
                    {
                        throw new EvaluationException(b.BaseExpression, "Shift operand must be between 0 and 31", b);
                    }

                    switch (x.OperatorToken)
                    {
                    case DTokens.ShiftLeft:
                        return (long)a.Value << (int)b.Value;                                 // TODO: Handle the imaginary part

                    case DTokens.ShiftRight:
                        return (long)a.Value >> (int)b.Value;

                    case DTokens.ShiftRightUnsigned:                             //TODO: Find out where's the difference between >> and >>>
                        return (ulong)a.Value >> (int)(uint)b.Value;
                    }

                    throw new EvaluationException(x, "Invalid token for shift expression", l, r);
                }));
            }
            else if (x is AddExpression)
            {
                return(HandleSingleMathOp(x, l, r, (a, b, op) =>
                {
                    switch (op.OperatorToken)
                    {
                    case DTokens.Plus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart);

                    case DTokens.Minus:
                        return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart);
                    }

                    throw new EvaluationException(x, "Invalid token for add/sub expression", l, r);
                }));
            }
            else if (x is CatExpression)
            {
                // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array

                var av_l = l as ArrayValue;
                var av_r = r as ArrayValue;

                if (av_l != null && av_r != null)
                {
                    // Ensure that both arrays are of the same type
                    if (!ResultComparer.IsEqual(av_l.RepresentedType, av_r.RepresentedType))
                    {
                        throw new EvaluationException(x, "Both arrays must be of same type", l, r);
                    }

                    // Might be a string
                    if (av_l.IsString && av_r.IsString)
                    {
                        return(new ArrayValue(av_l.RepresentedType as ArrayType, x, av_l.StringValue + av_r.StringValue));
                    }
                    else
                    {
                        var elements = new ISymbolValue[av_l.Elements.Length + av_r.Elements.Length];
                        Array.Copy(av_l.Elements, 0, elements, 0, av_l.Elements.Length);
                        Array.Copy(av_r.Elements, 0, elements, av_l.Elements.Length, av_r.Elements.Length);

                        return(new ArrayValue(av_l.RepresentedType as ArrayType, elements));
                    }
                }

                ArrayType at = null;

                // Append the right value to the array
                if (av_l != null && (at = av_l.RepresentedType as ArrayType) != null &&
                    ResultComparer.IsImplicitlyConvertible(r.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[av_l.Elements.Length + 1];
                    Array.Copy(av_l.Elements, elements, av_l.Elements.Length);
                    elements[elements.Length - 1] = r;

                    return(new ArrayValue(at, elements));
                }
                // Put the left value into the first position
                else if (av_r != null && (at = av_r.RepresentedType as ArrayType) != null &&
                         ResultComparer.IsImplicitlyConvertible(l.RepresentedType, at.ValueType, ctxt))
                {
                    var elements = new ISymbolValue[1 + av_r.Elements.Length];
                    elements[0] = l;
                    Array.Copy(av_r.Elements, 0, elements, 1, av_r.Elements.Length);

                    return(new ArrayValue(at, elements));
                }

                throw new EvaluationException(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", l, r);
            }

            throw new WrongEvaluationArgException();
        }
Beispiel #11
0
        public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol)
        {
            DSymbol ds = null;

            mightBeLegalUnresolvableSymbol = false;

            if (string.IsNullOrWhiteSpace(symName))
            {
                return(null);
            }

            // Try to handle a probably mangled string or C function.
            if (symName.StartsWith("_"))
            {
                try{
                    ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol;
                }catch {}
            }

            // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[])
            if (ds == null && Lexer.IsIdentifierPart((int)symName[0]))
            {
                mightBeLegalUnresolvableSymbol = true;
                ITypeDeclaration q;
                var method = DParser.ParseMethodDeclarationHeader(symName, out q);
                q = Demangler.RemoveNestedTemplateRefsFromQualifier(q);

                AbstractType[] overloads = null;
                D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => {
                    try {
                        overloads = AmbiguousType.TryDissolve(LooseResolution.LookupIdRawly(ctxt.ParseCache, q, ctxt.ScopedBlock.NodeRoot as DModule)).ToArray();
                    }
                    catch (Exception ex) { MonoDevelop.Core.LoggingService.LogWarning("Error during trace.log symbol resolution of " + q.ToString(), ex); }
                });

                if (overloads == null || overloads.Length == 0)
                {
                    return(null);
                }
                else if (overloads.Length == 1)
                {
                    ds = overloads[0] as DSymbol;
                }
                else
                {
                    method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type);
                    var methodType = TypeDeclarationResolver.GetMethodReturnType(method, ctxt);

                    var methodParameters = new List <AbstractType>();
                    D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => {
                        if (method.Parameters != null && method.Parameters.Count != 0)
                        {
                            foreach (var parm in method.Parameters)
                            {
                                methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt));
                            }
                        }
                    });

                    foreach (var o in overloads)
                    {
                        ds = o as DSymbol;
                        if (ds == null || !(ds.Definition is DMethod))
                        {
                            continue;
                        }

                        var dm = ds.Definition as DMethod;
                        // Compare return types
                        if (dm.Type != null)
                        {
                            if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base))
                            {
                                continue;
                            }
                        }
                        else if (dm.Type == null && methodType != null)
                        {
                            return(null);
                        }

                        // Compare parameters
                        if (methodParameters.Count != dm.Parameters.Count)
                        {
                            continue;
                        }

                        for (int i = 0; i < methodParameters.Count; i++)
                        {
                            if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt)))
                            {
                                continue;
                            }
                        }
                    }
                }
            }

            return(ds != null ? ds.Definition : null);
        }