Esempio n. 1
0
        public IEnumerable <DMethod> FindFitting(ResolverContextStack ctxt, CodeLocation currentLocation, ISemantic firstArgument, string nameFilter = null)
        {
            if (IsProcessing)
            {
                return(null);
            }

            var preMatchList = new List <DMethod>();

            bool dontUseNameFilter = nameFilter == null;

            lock (CachedMethods)
                foreach (var kv in CachedMethods)
                {
                    // First test if arg is matching the parameter
                    if ((dontUseNameFilter || kv.Key.Name == nameFilter) &&
                        ResultComparer.IsImplicitlyConvertible(firstArgument, kv.Value, ctxt))
                    {
                        preMatchList.Add(kv.Key);
                    }
                }

            // Then filter out methods which cannot be accessed in the current context
            // (like when the method is defined in a module that has not been imported)
            var mv = new MatchFilterVisitor <DMethod>(ctxt, preMatchList);

            mv.IterateThroughScopeLayers(currentLocation);

            return(mv.filteredList);
        }
        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)));
        }
Esempio n. 3
0
        void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null)
        {
            if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null)
            {
                var pop = ctxt.ScopedBlock != dm;
                if (pop)
                {
                    ctxt.PushNewScope(dm);
                }

                var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters [0].Type, ctxt);
                if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt))
                {
                    var res = alreadyResolvedMethod ?? new MemberSymbol(dm, null, sr);
                    res.Tag = new UfcsTag {
                        firstArgument = firstArgument
                    };
                    matches.Add(res);
                }

                if (pop)
                {
                    ctxt.Pop();
                }
            }
        }
        bool Handle(TemplateValueParameter p, ISemantic arg)
        {
            // Handle default arg case
            if (arg == null)
            {
                if (p.DefaultExpression != null)
                {
                    var eval = Evaluation.EvaluateValue(p.DefaultExpression, ctxt);

                    if (eval == null)
                    {
                        return(false);
                    }

                    return(Set(p, eval));
                }
                else
                {
                    return(false);
                }
            }

            var valueArgument = arg as ISymbolValue;

            // There must be a constant expression given!
            if (valueArgument == null)
            {
                return(false);
            }

            // Check for param type <-> arg expression type match
            var paramType = TypeDeclarationResolver.Resolve(p.Type, ctxt);

            if (paramType == null || paramType.Length == 0)
            {
                return(false);
            }

            if (valueArgument.RepresentedType == null ||
                !ResultComparer.IsImplicitlyConvertible(paramType[0], valueArgument.RepresentedType))
            {
                return(false);
            }

            // If spec given, test for equality (only ?)
            if (p.SpecializationExpression != null)
            {
                var specVal = Evaluation.EvaluateValue(p.SpecializationExpression, ctxt);

                if (specVal == null || !SymbolValueComparer.IsEqual(specVal, valueArgument))
                {
                    return(false);
                }
            }

            return(Set(p, arg));
        }
        bool HandleDecl(TypeOfDeclaration t, AbstractType r)
        {
            // Can I enter some template parameter referencing id into a typeof specialization!?
            // class Foo(T:typeof(1)) {} ?
            var t_res = TypeDeclarationResolver.Resolve(t, ctxt);

            if (t_res == null)
            {
                return(false);
            }

            return(ResultComparer.IsImplicitlyConvertible(r, t_res));
        }
Esempio n. 6
0
        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);
        }
Esempio n. 7
0
            protected override bool HandleItem(INode n)
            {
                AbstractType t;

                if (n is DMethod &&
                    (nameFilterHash == 0 || n.NameHash == nameFilterHash) &&
                    cache.TryGetValue(n as DMethod, out t) &&
                    ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt))
                {
                    filteredMethods.Add(n as DMethod);
                }

                return(false);
            }
Esempio n. 8
0
        public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value)
        {
            var oldV = vp[Variable];

            if (oldV is ArrayValue)
            {
                var av = (ArrayValue)oldV;

                //TODO: Immutability checks

                if (av.IsString)
                {
                }
                else
                {
                    var at          = av.RepresentedType as ArrayType;
                    var newElements = new ISymbolValue[av.Elements.Length + (ItemNumber < 0 ? 1:0)];
                    av.Elements.CopyTo(newElements, 0);

                    if (!ResultComparer.IsImplicitlyConvertible(value.RepresentedType, at.ValueType))
                    {
                        if (vp.ev != null)
                        {
                            vp.ev.EvalError(null, value.ToCode() + " must be implicitly convertible to the array's value type!", value);
                        }
                        return;
                    }

                    // Add..
                    if (ItemNumber < 0)
                    {
                        av.Elements[av.Elements.Length - 1] = value;
                    }
                    else                     // or set the new value
                    {
                        av.Elements[ItemNumber] = value;
                    }

                    vp[Variable] = new ArrayValue(at, newElements);
                }
            }
            else
            {
                if (vp.ev != null)
                {
                    vp.ev.EvalError(null, "Type of accessed item must be an array", oldV);
                }
            }
        }
        bool HandleDecl(VectorDeclaration v, AbstractType r)
        {
            if (r.DeclarationOrExpressionBase is VectorDeclaration)
            {
                var v_res = ExpressionTypeEvaluation.EvaluateType(v.Id, ctxt);
                var r_res = ExpressionTypeEvaluation.EvaluateType(((VectorDeclaration)r.DeclarationOrExpressionBase).Id, ctxt);

                if (v_res == null || r_res == null)
                {
                    return(false);
                }
                else
                {
                    return(ResultComparer.IsImplicitlyConvertible(r_res, v_res));
                }
            }
            return(false);
        }
Esempio n. 10
0
 void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null)
 {
     if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null)
     {
         var loc = dm.Body != null ? dm.Body.Location : dm.Location;
         using (alreadyResolvedMethod != null ? ctxt.Push(alreadyResolvedMethod, loc) : ctxt.Push(dm, loc))
         {
             var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters[0].Type, ctxt);
             if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt))
             {
                 var res = alreadyResolvedMethod ?? TypeDeclarationResolver.HandleNodeMatch(dm, ctxt, typeBase: sr);
                 res.Tag = new UfcsTag {
                     firstArgument = firstArgument
                 };
                 matches.Add(res);
             }
         }
     }
 }
Esempio n. 11
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);
        }
Esempio n. 13
0
        ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true)
        {
            // Deduce template parameters later on
            AbstractType[]             baseExpression = null;
            ISymbolValue               baseValue      = null;
            TemplateInstanceExpression tix            = null;
            bool isUFCSFunction = false;

            GetRawCallOverloads(call, out baseExpression, out baseValue, out tix, out isUFCSFunction);

            var methodOverloads = new List <AbstractType>();

            #region Search possible methods, opCalls or delegates that could be called
            bool requireStaticItems = true;             //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit
            IEnumerable <AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression);
            var nextResults = new List <AbstractType>();

            while (scanResults != null)
            {
                foreach (var b in scanResults)
                {
                    if (b is MemberSymbol)
                    {
                        var mr = (MemberSymbol)b;

                        if (mr.Definition is DMethod)
                        {
                            methodOverloads.Add(mr);
                            continue;
                        }
                        else if (mr.Definition is DVariable)
                        {
                            // If we've got a variable here, get its base type/value reference
                            if (eval)
                            {
                                var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue;

                                if (dgVal != null)
                                {
                                    nextResults.Add(dgVal.Definition);
                                    continue;
                                }
                                else
                                {
                                    throw new EvaluationException(call, "Variable must be a delegate, not anything else", mr);
                                }
                            }
                            else
                            {
                                var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt));

                                // Must be of type delegate
                                if (bt is DelegateType)
                                {
                                    //TODO: Ensure that there's no further overload - inform the user elsewise

                                    if (returnBaseTypeOnly)
                                    {
                                        return(bt);
                                    }
                                    else
                                    {
                                        return(new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase));
                                    }
                                }
                                else
                                {
                                    /*
                                     * If mr.Node is not a method, so e.g. if it's a variable
                                     * pointing to a delegate
                                     *
                                     * class Foo
                                     * {
                                     *	string opCall() {  return "asdf";  }
                                     * }
                                     *
                                     * Foo f=new Foo();
                                     * f(); -- calls opCall, opCall is not static
                                     */
                                    nextResults.Add(bt);
                                    requireStaticItems = false;
                                }
                                //TODO: Can other types work as function/are callable?
                            }
                        }
                    }
                    else if (b is DelegateType)
                    {
                        var dg = (DelegateType)b;

                        /*
                         * int a = delegate(x) { return x*2; } (12); // a is 24 after execution
                         * auto dg=delegate(x) {return x*3;};
                         * int b = dg(4);
                         */

                        if (dg.IsFunctionLiteral)
                        {
                            methodOverloads.Add(dg);
                        }
                        else
                        {
                            // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method.
                            if (eval)
                            {
                                throw new EvaluationException(call, "TODO", dg);
                            }
                            //TODO
                            //if(returnBaseTypeOnly)
                            //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments.
                            return(dg);
                        }
                    }
                    else if (b is ClassType)
                    {
                        /*
                         * auto a = MyStruct(); -- opCall-Overloads can be used
                         */
                        var classDef = ((ClassType)b).Definition;

                        if (classDef == null)
                        {
                            continue;
                        }

                        foreach (var i in classDef)
                        {
                            if (i.Name == "opCall" && i is DMethod && (!requireStaticItems || (i as DNode).IsStatic))
                            {
                                methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol);
                            }
                        }
                    }

                    /*
                     * Every struct can contain a default ctor:
                     *
                     * struct S { int a; bool b; }
                     *
                     * auto s = S(1,true); -- ok
                     * auto s2= new S(2,false); -- error, no constructor found!
                     */
                    else if (b is StructType && methodOverloads.Count == 0)
                    {
                        //TODO: Deduce parameters
                        return(b);
                    }

                    /*
                     * If the overload is a template, it quite exclusively means that we'll handle a method that is the only
                     * child inside a template + that is named as the template.
                     */
                    else if (b is TemplateType &&
                             ImplicitTemplateProperties.ContainsEquallyNamedChildrenOnly(((TemplateType)b).Definition))
                    {
                        methodOverloads.Add(b);
                    }
                }

                scanResults = nextResults.Count == 0 ? null : nextResults.ToArray();
                nextResults.Clear();
            }
            #endregion

            if (methodOverloads.Count == 0)
            {
                return(null);
            }

            // Get all arguments' types
            var callArguments = new List <ISemantic>();

            // If it's sure that we got a ufcs call here, add the base expression's type as first argument type
            if (isUFCSFunction)
            {
                callArguments.Add(eval ? (ISemantic)baseValue : ((MemberSymbol)baseExpression[0]).Base);
            }

            if (call.Arguments != null)
            {
                foreach (var arg in call.Arguments)
                {
                    callArguments.Add(E(arg));
                }
            }

            #region Deduce template parameters and filter out unmatching overloads
            // First add optionally given template params
            // http://dlang.org/template.html#function-templates
            var tplParamDeductionArguments = tix == null ?
                                             new List <ISemantic>() :
                                             TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt);

            // Then add the arguments[' member types]
            foreach (var arg in callArguments)
            {
                if (arg is VariableValue)
                {
                    tplParamDeductionArguments.Add(ValueProvider[((VariableValue)arg).Variable]);
                }
                else if (arg is AbstractType)
                {
                    tplParamDeductionArguments.Add(DResolver.StripMemberSymbols((AbstractType)arg));
                }
                else
                {
                    tplParamDeductionArguments.Add(arg);
                }
            }

            var templateParamFilteredOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(
                methodOverloads,
                tplParamDeductionArguments.Count > 0 ? tplParamDeductionArguments.ToArray() : null,
                true, ctxt);
            #endregion

            #region Filter by parameter-argument comparison
            var argTypeFilteredOverloads = new List <AbstractType>();

            if (templateParamFilteredOverloads != null)
            {
                foreach (var ov in templateParamFilteredOverloads)
                {
                    if (ov is MemberSymbol)
                    {
                        var  ms  = (MemberSymbol)ov;
                        var  dm  = ms.Definition as DMethod;
                        bool add = false;

                        if (dm != null)
                        {
                            ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms);

                            add = false;

                            if (callArguments.Count == 0 && dm.Parameters.Count == 0)
                            {
                                add = true;
                            }
                            else
                            {
                                for (int i = 0; i < dm.Parameters.Count; i++)
                                {
                                    var paramType = TypeDeclarationResolver.ResolveSingle(dm.Parameters[i].Type, ctxt);

                                    // TODO: Expression tuples & variable argument lengths
                                    if (i >= callArguments.Count ||
                                        !ResultComparer.IsImplicitlyConvertible(callArguments[i], paramType, ctxt))
                                    {
                                        continue;
                                    }

                                    add = true;
                                }
                            }

                            if (add)
                            {
                                var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt);

                                if (returnBaseTypeOnly)
                                {
                                    argTypeFilteredOverloads.Add(bt);
                                }
                                else
                                {
                                    argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms);
                                }
                            }

                            ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms);
                        }
                    }
                    else if (ov is DelegateType)
                    {
                        var dg = (DelegateType)ov;
                        var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt);

                        //TODO: Param-Arg check
                        if (returnBaseTypeOnly)
                        {
                            argTypeFilteredOverloads.Add(bt);
                        }
                        else
                        {
                            argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters));
                        }
                    }
                }
            }
            #endregion

            if (eval)
            {
                // Convert ISemantic[] to ISymbolValue[]
                var args = new List <ISymbolValue>(callArguments.Count);

                foreach (var a in callArguments)
                {
                    args.Add(a as ISymbolValue);
                }

                // Execute/Evaluate the variable contents etc.
                return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray()));
            }
            else
            {
                // Check if one overload remains and return that one.
                ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call);
                return(argTypeFilteredOverloads != null && argTypeFilteredOverloads.Count != 0 ?
                       argTypeFilteredOverloads[0] : null);
            }
        }
        /// <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();
        }
        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()));
        }
Esempio n. 16
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);
        }
Esempio n. 17
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);
        }