예제 #1
0
        public int GetCurrentParameterIndex(CodeLocation where)
        {
            /*
             * if(args.ParsedExpression is PostfixExpression_MethodCall)
             * {
             *      var mc = args.ParsedExpression as PostfixExpression_MethodCall;
             *
             *      if(mc.ArgumentCount == 0)
             *              return 0;
             *      for(int i = 0; i < mc.ArgumentCount; i++)
             *      {
             *              if(where <= mc.Arguments[i].EndLocation)
             *                      return i+1;
             *      }
             * }*/
            var       idx = args.CurrentlyTypedArgumentIndex;
            var       ms  = CurrentResult as MemberSymbol;
            ISemantic _u;

            if (ms != null && UFCSResolver.IsUfcsResult(ms, out _u))
            {
                idx++;
            }
            return(idx);
        }
예제 #2
0
 void GenUfcsAndStaticProperties(AbstractType t)
 {
     if (isVariableInstance && CompletionOptions.Instance.ShowUFCSItems)
     {
         foreach (var ufcsItem in UFCSResolver.TryResolveUFCS(t, 0, ed.CaretLocation, ctxt))
         {
             CompletionDataGenerator.Add((ufcsItem as DSymbol).Definition);
         }
     }
     StaticProperties.ListProperties(CompletionDataGenerator, MemberFilter, t, isVariableInstance);
 }
예제 #3
0
 void GenUfcsAndStaticProperties(AbstractType t)
 {
     if (t.NonStaticAccess && CompletionOptions.Instance.ShowUFCSItems)
     {
         CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () =>
         {
             foreach (var ufcsItem in UFCSResolver.TryResolveUFCS(t, 0, ed.CaretLocation, ctxt))
             {
                 CompletionDataGenerator.Add((ufcsItem as DSymbol).Definition);
             }
         });
     }
     StaticProperties.ListProperties(CompletionDataGenerator, ctxt, MemberFilter, t, t.NonStaticAccess);
 }
        static void HandleDMethodOverload(ResolutionContext ctxt, bool eval, ISymbolValue baseValue, List <ISemantic> callArguments, bool returnBaseTypeOnly, List <AbstractType> argTypeFilteredOverloads, ref bool hasHandledUfcsResultBefore,
                                          MemberSymbol ms, ref AbstractType untemplatedMethod)
        {
            var dm = ms.Definition as DMethod;

            if (dm == null)
            {
                return;
            }



            ISemantic firstUfcsArg;
            bool      isUfcs = UFCSResolver.IsUfcsResult(ms, out firstUfcsArg);

            // In the case of an ufcs, insert the first argument into the CallArguments list
            if (isUfcs && !hasHandledUfcsResultBefore)
            {
                callArguments.Insert(0, eval ? baseValue as ISemantic : firstUfcsArg);
                hasHandledUfcsResultBefore = true;
            }
            else if (!isUfcs && hasHandledUfcsResultBefore)             // In the rare case of having a ufcs result occuring _after_ a normal member result, remove the initial arg again
            {
                callArguments.RemoveAt(0);
                hasHandledUfcsResultBefore = false;
            }

            if (dm.Parameters.Count == 0 && callArguments.Count > 0)
            {
                return;
            }

            var deducedTypeDict        = new DeducedTypeDictionary(ms);
            var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt);

            var back = ctxt.ScopedBlock;

            using (ctxt.Push(ms))
            {
                if (ctxt.ScopedBlock != back)
                {
                    ctxt.CurrentContext.DeducedTemplateParameters = deducedTypeDict;
                }

                bool add        = true;
                int  currentArg = 0;
                if (dm.Parameters.Count > 0 || callArguments.Count > 0)
                {
                    bool hadDTuples = false;
                    for (int i = 0; i < dm.Parameters.Count; i++)
                    {
                        var paramType = dm.Parameters[i].Type;

                        // Handle the usage of tuples: Tuples may only be used as as-is, so not as an array, pointer or in a modified way..
                        if (paramType is IdentifierDeclaration &&
                            (hadDTuples |= TryHandleMethodArgumentTuple(ctxt, ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)))
                        {
                            continue;
                        }
                        else if (currentArg < callArguments.Count)
                        {
                            if (!(add = templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])))
                            {
                                break;
                            }
                        }
                        else
                        {
                            // If there are more parameters than arguments given, check if the param has default values
                            add = !(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer != null;

                            // Assume that all further method parameters do have default values - and don't check further parameters
                            break;
                        }
                    }

                    // Too few args
                    if (!hadDTuples && currentArg < callArguments.Count)
                    {
                        add = false;
                    }
                }

                if (!add)
                {
                    return;
                }

                // If type params were unassigned, try to take the defaults
                if (dm.TemplateParameters != null)
                {
                    foreach (var tpar in dm.TemplateParameters)
                    {
                        if (deducedTypeDict[tpar] == null && !templateParamDeduction.Handle(tpar, null))
                        {
                            return;
                        }
                    }
                }

                if (deducedTypeDict.AllParamatersSatisfied)
                {
                    ms.DeducedTypes = deducedTypeDict.ToReadonly();
                    var bt = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt) ?? ms.Base;

                    if (eval || !returnBaseTypeOnly)
                    {
                        bt = new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes)
                        {
                            Tag = ms.Tag
                        }
                    }
                    ;

                    if (dm.TemplateParameters == null || dm.TemplateParameters.Length == 0)
                    {
                        untemplatedMethod = bt;                         //ISSUE: Have another state that indicates an ambiguous non-templated method matching.
                    }
                    argTypeFilteredOverloads.Add(bt);
                }
            }
        }
예제 #5
0
        /// <summary>
        /// Returns either all unfiltered and undeduced overloads of a member of a base type/value (like b from type a if the expression is a.b).
        /// if <param name="EvalAndFilterOverloads"></param> is false.
        /// If true, all overloads will be deduced, filtered and evaluated, so that (in most cases,) a one-item large array gets returned
        /// which stores the return value of the property function b that is executed without arguments.
        /// Also handles UFCS - so if filtering is wanted, the function becom
        /// </summary>
        ISemantic[] E(PostfixExpression_Access acc,
                      ISemantic resultBase = null, bool EvalAndFilterOverloads = true, bool ResolveImmediateBaseType = true)
        {
            if (acc == null)
            {
                return(null);
            }

            var baseExpression = resultBase ?? E(acc.PostfixForeExpression);

            if (acc.AccessExpression is NewExpression)
            {
                /*
                 * This can be both a normal new-Expression as well as an anonymous class declaration!
                 */
                //TODO!
                return(null);
            }


            AbstractType[] overloads;
            var            optBackup = ctxt.CurrentContext.ContextDependentOptions;

            if (acc.AccessExpression is TemplateInstanceExpression)
            {
                if (!ResolveImmediateBaseType)
                {
                    ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes;
                }

                var tix = (TemplateInstanceExpression)acc.AccessExpression;
                // Do not deduce and filter if superior expression is a method call since call arguments' types also count as template arguments!
                overloads = GetOverloads(tix, new[] { AbstractType.Get(baseExpression) }, EvalAndFilterOverloads);

                if (!ResolveImmediateBaseType)
                {
                    ctxt.CurrentContext.ContextDependentOptions = optBackup;
                }
            }

            else if (acc.AccessExpression is IdentifierExpression)
            {
                var id = acc.AccessExpression as IdentifierExpression;

                if (eval && EvalAndFilterOverloads && resultBase != null)
                {
                    var staticPropResult = StaticProperties.TryEvalPropertyValue(ValueProvider, resultBase, id.ValueStringHash);
                    if (staticPropResult != null)
                    {
                        return new[] { staticPropResult }
                    }
                    ;
                }

                if (!ResolveImmediateBaseType)
                {
                    ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes;
                }

                overloads = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(id.ValueStringHash, new[] { AbstractType.Get(baseExpression) }, ctxt, acc.AccessExpression);

                if (!ResolveImmediateBaseType)
                {
                    ctxt.CurrentContext.ContextDependentOptions = optBackup;
                }
            }
            else
            {
                if (eval)
                {
                    EvalError(acc, "Invalid access expression");
                    return(null);
                }
                ctxt.LogError(acc, "Invalid post-dot expression");
                return(null);
            }

            /*
             * Try to get ufcs functions at first!
             *
             * void foo(int i) {}
             *
             * class A
             * {
             *	void foo(int i, int a) {}
             *
             *	void bar(){
             *		123.foo(23); // Not allowed!
             *		// Anyway, if we tried to search ufcs functions AFTER searching from child to parent scope levels,
             *		// it would return the local foo() only, not the global one..which would be an error then!
             *  }
             *
             * Probably also worth to notice is the property syntax..are property functions rather preferred than ufcs ones?
             * }
             */
            if (overloads == null || EvalAndFilterOverloads)
            {
                var oo = UFCSResolver.TryResolveUFCS(baseExpression, acc, ctxt) as AbstractType[];

                if (oo != null)
                {
                    int overloadsLength = overloads == null ? 0 : overloads.Length;
                    var newArr          = new AbstractType[overloadsLength + oo.Length];
                    if (overloadsLength != 0)
                    {
                        overloads.CopyTo(newArr, 0);
                    }
                    oo.CopyTo(newArr, overloadsLength);
                    overloads = newArr;
                }
            }

            // If evaluation active and the access expression is stand-alone, return a single item only.
            if (EvalAndFilterOverloads && eval)
            {
                return new[] { TryDoCTFEOrGetValueRefs(overloads, acc.AccessExpression) }
            }
            ;

            return(overloads);
        }

        ISemantic E(PostfixExpression_Index x, ISemantic foreExpression)
        {
            if (eval)
            {
                //TODO: Access pointer arrays(?)

                if (foreExpression is ArrayValue)                 // ArrayValue must be checked first due to inheritance!
                {
                    var av = foreExpression as ArrayValue;

                    // Make $ operand available
                    var arrLen_Backup = ValueProvider.CurrentArrayLength;
                    ValueProvider.CurrentArrayLength = av.Elements.Length;

                    var n = E(x.Arguments[0]) as PrimitiveValue;

                    ValueProvider.CurrentArrayLength = arrLen_Backup;

                    if (n == null)
                    {
                        EvalError(x.Arguments[0], "Returned no value");
                        return(null);
                    }

                    int i = 0;
                    try{
                        i = Convert.ToInt32(n.Value);
                    }
                    catch
                    {
                        EvalError(x.Arguments[0], "Index expression must be of type int");
                        return(null);
                    }

                    if (i < 0 || i > av.Elements.Length)
                    {
                        EvalError(x.Arguments[0], "Index out of range - it must be between 0 and " + av.Elements.Length);
                        return(null);
                    }

                    return(av.Elements[i]);
                }
                else if (foreExpression is AssociativeArrayValue)
                {
                    var aa = (AssociativeArrayValue)foreExpression;

                    var key = E(x.Arguments[0]);

                    if (key == null)
                    {
                        EvalError(x.Arguments[0], "Returned no value");
                        return(null);
                    }

                    ISymbolValue val = null;

                    foreach (var kv in aa.Elements)
                    {
                        if (kv.Key.Equals(key))
                        {
                            return(kv.Value);
                        }
                    }

                    EvalError(x, "Could not find key '" + val + "'");
                    return(null);
                }

                EvalError(x.PostfixForeExpression, "Invalid index expression base value type", foreExpression);

                return(null);
            }
            else
            {
                foreExpression = DResolver.StripMemberSymbols(AbstractType.Get(foreExpression));

                if (foreExpression is AssocArrayType)
                {
                    var ar = foreExpression as AssocArrayType;

                    /*
                     * myType_Array[0] -- returns TypeResult myType
                     * return the value type of a given array result
                     */
                    //TODO: Handle opIndex overloads

                    return(new ArrayAccessSymbol(x, ar.ValueType));
                }

                /*
                 * int* a = new int[10];
                 *
                 * a[0] = 12;
                 */
                else if (foreExpression is PointerType)
                {
                    return((foreExpression as PointerType).Base);
                }
                //return new ArrayAccessSymbol(x,((PointerType)foreExpression).Base);

                else if (foreExpression is DTuple)
                {
                    var tt = foreExpression as DTuple;

                    if (x.Arguments != null && x.Arguments.Length != 0)
                    {
                        var idx = EvaluateValue(x.Arguments[0], ctxt) as PrimitiveValue;

                        if (idx == null || !DTokens.BasicTypes_Integral[idx.BaseTypeToken])
                        {
                            ctxt.LogError(x.Arguments[0], "Index expression must evaluate to integer value");
                        }
                        else if (idx.Value > (decimal)Int32.MaxValue ||
                                 (int)idx.Value >= tt.Items.Length ||
                                 (int)idx.Value < 0)
                        {
                            ctxt.LogError(x.Arguments[0], "Index number must be a value between 0 and " + tt.Items.Length);
                        }
                        else
                        {
                            return(tt.Items[(int)idx.Value]);
                        }
                    }
                }

                ctxt.LogError(new ResolutionError(x, "Invalid base type for index expression"));
            }

            return(null);
        }

        ISemantic E(PostfixExpression_Slice x, ISemantic foreExpression)
        {
            if (!eval)
            {
                return(foreExpression);                // Still of the array's type.
            }
            if (!(foreExpression is ArrayValue))
            {
                EvalError(x.PostfixForeExpression, "Must be an array");
                return(null);
            }

            var ar = (ArrayValue)foreExpression;
            var sl = (PostfixExpression_Slice)x;

            // If the [ ] form is used, the slice is of the entire array.
            if (sl.FromExpression == null && sl.ToExpression == null)
            {
                return(foreExpression);
            }

            // Make $ operand available
            var arrLen_Backup = ValueProvider.CurrentArrayLength;

            ValueProvider.CurrentArrayLength = ar.Elements.Length;

            var bound_lower = E(sl.FromExpression) as PrimitiveValue;
            var bound_upper = E(sl.ToExpression) as PrimitiveValue;

            ValueProvider.CurrentArrayLength = arrLen_Backup;

            if (bound_lower == null || bound_upper == null)
            {
                EvalError(bound_lower == null ? sl.FromExpression : sl.ToExpression, "Must be of an integral type");
                return(null);
            }

            int lower = -1, upper = -1;

            try
            {
                lower = Convert.ToInt32(bound_lower.Value);
                upper = Convert.ToInt32(bound_upper.Value);
            }
            catch { EvalError(lower != -1 ? sl.FromExpression : sl.ToExpression, "Boundary expression must base an integral type");
                    return(null); }

            if (lower < 0)
            {
                EvalError(sl.FromExpression, "Lower boundary must be greater than 0"); return(null);
            }
            if (lower >= ar.Elements.Length)
            {
                EvalError(sl.FromExpression, "Lower boundary must be smaller than " + ar.Elements.Length); return(null);
            }
            if (upper < lower)
            {
                EvalError(sl.ToExpression, "Upper boundary must be greater than " + lower); return(null);
            }
            if (upper >= ar.Elements.Length)
            {
                EvalError(sl.ToExpression, "Upper boundary must be smaller than " + ar.Elements.Length); return(null);
            }


            var rawArraySlice = new ISymbolValue[upper - lower];
            int j             = 0;

            for (int i = lower; i < upper; i++)
            {
                rawArraySlice[j++] = ar.Elements[i];
            }

            return(new ArrayValue(ar.RepresentedType as ArrayType, rawArraySlice));
        }

        ISemantic E(PostfixExpression_Increment x, ISemantic foreExpression)
        {
            // myInt++ is still of type 'int'
            if (!eval)
            {
                return(foreExpression);
            }

            if (resolveConstOnly)
            {
                EvalError(new NoConstException(x));
            }
            // Must be implemented anyway regarding ctfe
            return(null);
        }

        ISemantic E(PostfixExpression_Decrement x, ISemantic foreExpression)
        {
            if (!eval)
            {
                return(foreExpression);
            }

            if (resolveConstOnly)
            {
                EvalError(new NoConstException(x));
            }
            // Must be implemented anyway regarding ctfe
            return(null);
        }
    }
}