public override void Visit(PostfixExpression_MethodCall x) { base.Visit(x); if (IdNearCaret == x.PostfixForeExpression) { IdNearCaret = x; } }
public AbstractType Visit(PostfixExpression_MethodCall call) { List <ISemantic> callArgs; ISymbolValue delegValue; AbstractType[] baseExpression; TemplateInstanceExpression tix; GetRawCallOverloads(ctxt, call.PostfixForeExpression, out baseExpression, out tix); return(Evaluation.EvalMethodCall(baseExpression, null, tix, ctxt, call, out callArgs, out delegValue, !ctxt.Options.HasFlag(ResolutionOptions.ReturnMethodReferencesOnly))); }
public void Visit(PostfixExpression_MethodCall call) { res.IsMethodArguments = true; res.MethodIdentifier = call.PostfixForeExpression; res.ResolvedTypesOrMethods = ExpressionTypeEvaluation.GetUnfilteredMethodOverloads(call.PostfixForeExpression, ctxt, call); if (call.Arguments != null) { res.CurrentlyTypedArgumentIndex = call.ArgumentCount; } }
public override void Visit(PostfixExpression_MethodCall x) { if (triggerChar == '(' && x.ArgumentCount > 0 && IsIncompleteExpression(x.Arguments[x.ArgumentCount - 1])) { halt = true; explicitlyNoCompletion = true; } else { base.Visit(x); } }
public AbstractType Visit(PostfixExpression_MethodCall call) { List <ISemantic> callArgs; ISymbolValue delegValue; AbstractType[] baseExpression; TemplateInstanceExpression tix; GetRawCallOverloads(ctxt, call, out baseExpression, out tix); var argTypeFilteredOverloads = Evaluation.EvalMethodCall(baseExpression, null, tix, ctxt, call, out callArgs, out delegValue, !ctxt.Options.HasFlag(ResolutionOptions.ReturnMethodReferencesOnly)); // Check if one overload remains and return that one. ctxt.CheckForSingleResult(argTypeFilteredOverloads, call); return(argTypeFilteredOverloads != null && argTypeFilteredOverloads.Count != 0 ? argTypeFilteredOverloads[0] : null); }
public ISymbolValue Visit(PostfixExpression_MethodCall call) { var returnBaseTypeOnly = !this.returnBaseTypeOnly.HasValue ? !ctxt.Options.HasFlag(ResolutionOptions.ReturnMethodReferencesOnly) : this.returnBaseTypeOnly.Value; this.returnBaseTypeOnly = null; List <ISemantic> callArguments; ISymbolValue delegValue; // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(ctxt, call, out baseExpression, out baseValue, out tix); var argTypeFilteredOverloads = EvalMethodCall(baseExpression, baseValue, tix, ctxt, call, out callArguments, out delegValue, returnBaseTypeOnly, ValueProvider); if (delegValue != null) { return(delegValue); } if (argTypeFilteredOverloads == null) { return(null); } // Convert ISemantic[] to ISymbolValue[] var args = new List <ISymbolValue>(callArguments != null ? callArguments.Count : 0); if (callArguments != null) { foreach (var a in callArguments) { args.Add(a as ISymbolValue); } } // Execute/Evaluate the variable contents etc. return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads, call.PostfixForeExpression, true, args.ToArray())); }
void GetRawCallOverloads(ResolutionContext ctxt, PostfixExpression_MethodCall call, out AbstractType[] baseExpression, out TemplateInstanceExpression tix) { tix = null; if (call.PostfixForeExpression is PostfixExpression_Access) { var pac = (PostfixExpression_Access)call.PostfixForeExpression; tix = pac.AccessExpression as TemplateInstanceExpression; baseExpression = Evaluation.EvalPostfixAccessExpression(this, ctxt, pac, null, false, false); } else { // Explicitly don't resolve the methods' return types - it'll be done after filtering to e.g. resolve template types to the deduced one var optBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; if (call.PostfixForeExpression is TokenExpression) { baseExpression = ExpressionTypeEvaluation.GetResolvedConstructorOverloads((TokenExpression)call.PostfixForeExpression, ctxt); } else { if (call.PostfixForeExpression is TemplateInstanceExpression) { baseExpression = ExpressionTypeEvaluation.GetOverloads(tix = (TemplateInstanceExpression)call.PostfixForeExpression, ctxt, null, false); } else if (call.PostfixForeExpression is IdentifierExpression) { baseExpression = ExpressionTypeEvaluation.GetOverloads(call.PostfixForeExpression as IdentifierExpression, ctxt, deduceParameters: false); } else { baseExpression = new[] { call.PostfixForeExpression != null?AbstractType.Get(call.PostfixForeExpression.Accept(this)) : null } }; } ctxt.CurrentContext.ContextDependentOptions = optBackup; } }
IExpression PostfixExpression(IBlockNode Scope = null) { var curLastParsedObj = LastParsedObject; // PostfixExpression IExpression leftExpr = PrimaryExpression(Scope); if(curLastParsedObj==LastParsedObject) LastParsedObject = leftExpr; while (!IsEOF) { if (laKind == Dot) { Step(); var e = new PostfixExpression_Access { PostfixForeExpression=leftExpr }; LastParsedObject = e; leftExpr = e; if (laKind == New) e.AccessExpression = NewExpression(Scope); else if (IsTemplateInstance) e.AccessExpression = TemplateInstance(); else if (Expect(Identifier)) e.AccessExpression = new IdentifierExpression(t.Value) { Location=t.Location, EndLocation=t.EndLocation }; e.EndLocation = t.EndLocation; } else if (laKind == Increment || laKind == Decrement) { Step(); var e = t.Kind == Increment ? (PostfixExpression)new PostfixExpression_Increment() : new PostfixExpression_Decrement(); LastParsedObject = e; e.EndLocation = t.EndLocation; e.PostfixForeExpression = leftExpr; leftExpr = e; } // Function call else if (laKind == OpenParenthesis) { Step(); var ae = new PostfixExpression_MethodCall(); LastParsedObject = ae; ae.PostfixForeExpression = leftExpr; leftExpr = ae; if (laKind != CloseParenthesis) ae.Arguments = ArgumentList(Scope).ToArray(); Step(); ae.EndLocation = t.EndLocation; } // IndexExpression | SliceExpression else if (laKind == OpenSquareBracket) { Step(); if (laKind != CloseSquareBracket) { var firstEx = AssignExpression(Scope); // [ AssignExpression .. AssignExpression ] if (laKind == DoubleDot) { Step(); leftExpr = new PostfixExpression_Slice() { FromExpression = firstEx, PostfixForeExpression = leftExpr, ToExpression = AssignExpression(Scope) }; LastParsedObject = leftExpr; } // [ ArgumentList ] else if (laKind == CloseSquareBracket || laKind == (Comma)) { var args = new List<IExpression>(); args.Add(firstEx); if (laKind == Comma) { Step(); args.AddRange(ArgumentList(Scope)); } leftExpr = new PostfixExpression_Index() { PostfixForeExpression = leftExpr, Arguments = args.ToArray() }; LastParsedObject = leftExpr; } } else // Empty array literal = SliceExpression { leftExpr = new PostfixExpression_Slice() { PostfixForeExpression=leftExpr }; LastParsedObject = leftExpr; } Expect(CloseSquareBracket); if(leftExpr is PostfixExpression) ((PostfixExpression)leftExpr).EndLocation = t.EndLocation; } else break; } return leftExpr; }
public void Visit(PostfixExpression_MethodCall call) { res.IsMethodArguments = true; res.MethodIdentifier = call.PostfixForeExpression; res.ResolvedTypesOrMethods = ExpressionTypeEvaluation.GetUnfilteredMethodOverloads(call.PostfixForeExpression, ctxt, call); if (call.Arguments != null) res.CurrentlyTypedArgumentIndex = call.ArgumentCount; }
IExpression PostfixExpression(IBlockNode Scope = null) { IExpression leftExpr = null; /* * Despite the following syntax is an explicit UnaryExpression (see http://dlang.org/expression.html#UnaryExpression), * stuff like (MyType).init[] is actually allowed - so it's obviously a PostfixExpression! (Nov 13 2013) */ // ( Type ) . Identifier if (laKind == OpenParenthesis) { Lexer.StartPeek(); OverPeekBrackets(OpenParenthesis, false); var dotToken = Lexer.CurrentPeekToken; if (Lexer.CurrentPeekToken.Kind == DTokens.Dot && (Peek().Kind == DTokens.Identifier || Lexer.CurrentPeekToken.Kind == EOF)) { var wkParsing = AllowWeakTypeParsing; AllowWeakTypeParsing = true; Lexer.PushLookAheadBackup(); Step(); var startLoc = t.Location; var td = Type(); AllowWeakTypeParsing = wkParsing; /* * (a. -- expression: (a.myProp + 2) / b; * (int. -- must be expression anyway * (const).asdf -- definitely unary expression ("type") * (const). -- also treat it as type accessor */ if (td != null && laKind == CloseParenthesis && Lexer.CurrentPeekToken == dotToken) // Also take it as a type declaration if there's nothing following (see Expression Resolving) { Step(); // Skip to ) if (laKind == DTokens.Dot) { Step(); // Skip to . if ((laKind == DTokens.Identifier && Peek(1).Kind != Not && Peek(1).Kind != OpenParenthesis) || IsEOF) { Lexer.PopLookAheadBackup(); Step(); // Skip to identifier leftExpr = new UnaryExpression_Type() { Type = td, AccessIdentifier = t.Value, Location = startLoc, EndLocation = t.EndLocation }; } else Lexer.RestoreLookAheadBackup(); } else Lexer.RestoreLookAheadBackup(); } else Lexer.RestoreLookAheadBackup(); } } // PostfixExpression if(leftExpr == null) leftExpr = PrimaryExpression(Scope); while (!IsEOF) { switch (laKind) { case Dot: Step(); var pea = new PostfixExpression_Access { PostfixForeExpression = leftExpr }; leftExpr = pea; if (laKind == New) pea.AccessExpression = PostfixExpression(Scope); else if (IsTemplateInstance) pea.AccessExpression = TemplateInstance(Scope); else if (Expect(Identifier)) pea.AccessExpression = new IdentifierExpression(t.Value) { Location = t.Location, EndLocation = t.EndLocation }; else if (IsEOF) pea.AccessExpression = new TokenExpression(DTokens.Incomplete); pea.EndLocation = t.EndLocation; break; case Increment: case Decrement: Step(); var peid = t.Kind == Increment ? (PostfixExpression)new PostfixExpression_Increment() : new PostfixExpression_Decrement(); peid.EndLocation = t.EndLocation; peid.PostfixForeExpression = leftExpr; leftExpr = peid; break; // Function call case OpenParenthesis: Step(); var pemc = new PostfixExpression_MethodCall(); pemc.PostfixForeExpression = leftExpr; leftExpr = pemc; if (laKind == CloseParenthesis) Step(); else { pemc.Arguments = ArgumentList(Scope).ToArray(); Expect(CloseParenthesis); } if(IsEOF) pemc.EndLocation = CodeLocation.Empty; else pemc.EndLocation = t.EndLocation; break; // IndexExpression | SliceExpression case OpenSquareBracket: Step(); if (laKind != CloseSquareBracket) { var firstEx = AssignExpression(Scope); // [ AssignExpression .. AssignExpression ] if (laKind == DoubleDot) { Step(); leftExpr = new PostfixExpression_Slice() { FromExpression = firstEx, PostfixForeExpression = leftExpr, ToExpression = AssignExpression(Scope) }; } // [ ArgumentList ] else if (laKind == CloseSquareBracket || laKind == (Comma)) { var args = new List<IExpression>(); args.Add(firstEx); if (laKind == Comma) { Step(); args.AddRange(ArgumentList(Scope)); } leftExpr = new PostfixExpression_Index() { PostfixForeExpression = leftExpr, Arguments = args.ToArray() }; } } else // Empty array literal = SliceExpression { leftExpr = new PostfixExpression_Slice() { PostfixForeExpression=leftExpr }; } Expect(CloseSquareBracket); if(leftExpr is PostfixExpression) ((PostfixExpression)leftExpr).EndLocation = t.EndLocation; break; default: return leftExpr; } } return leftExpr; }
public override void Visit(PostfixExpression_MethodCall x) { CallExpressionStack.Push(x); base.Visit(x); CallExpressionStack.Pop(); }
ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true) { // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix); 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 { EvalError(call, "Variable must be a delegate, not anything else", mr); return(null); } } 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) { EvalError(call, "TODO", dg); return(null); } //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 || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) { continue; } foreach (var i in GetOpCalls(tit, requireStaticItems)) { 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! */ 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) { 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>(); bool hasNonFinalArgs = false; if (call.Arguments != null) { foreach (var arg in call.Arguments) { callArguments.Add(E(arg)); } } #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs); methodOverloads.Clear(); if (deducedOverloads != null) { methodOverloads.AddRange(deducedOverloads); } } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); bool hasHandledUfcsResultBefore = false; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { var ms = ov as MemberSymbol; var dm = ms.Definition as DMethod; if (dm != null) { // In the case of an ufcs, insert the first argument into the CallArguments list if (ms.IsUFCSResult && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument); hasHandledUfcsResultBefore = true; } else if (!ms.IsUFCSResult && 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; } var deducedTypeDict = new DeducedTypeDictionary(ms); if (dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (!deducedTypeDict.ContainsKey(tpar.NameHash)) { deducedTypeDict[tpar.NameHash] = null; } } } var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); int currentArg = 0; bool add = true; if (callArguments.Count > 0 || dm.Parameters.Count > 0) { 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 && TryHandleMethodArgumentTuple(ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) { continue; } else if (currentArg < callArguments.Count) { if (!templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])) { add = false; break; } } else { // If there are more parameters than arguments given, check if the param has default values if (!(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer == null) { add = false; break; } // Assume that all further method parameters do have default values - and don't check further parameters break; } } } // If type params were unassigned, try to take the defaults if (add && dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar.NameHash] == null) { add = templateParamDeduction.Handle(tpar, null); if (!add) { if (hasNonFinalArgs) { deducedTypeDict[tpar.NameHash] = new TemplateParameterSymbol(tpar, null); add = true; } else { break; } } } } } if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs)) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); if (eval || !returnBaseTypeOnly) { argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); } else { argTypeFilteredOverloads.Add(bt); } } } } else if (ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (!eval || 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.Count != 0 ? argTypeFilteredOverloads[0] : null); } }
void GetRawCallOverloads(PostfixExpression_MethodCall call, out AbstractType[] baseExpression, out ISymbolValue baseValue, out TemplateInstanceExpression tix) { baseExpression = null; baseValue = null; tix = null; if (call.PostfixForeExpression is PostfixExpression_Access) { var pac = (PostfixExpression_Access)call.PostfixForeExpression; tix = pac.AccessExpression as TemplateInstanceExpression; var vs = E(pac, null, false, false); if (vs != null && vs.Length != 0) { if (vs[0] is ISymbolValue) { baseValue = (ISymbolValue)vs[0]; baseExpression = new[] { baseValue.RepresentedType }; } else if (vs[0] is InternalOverloadValue) { baseExpression = ((InternalOverloadValue)vs[0]).Overloads; } else { baseExpression = TypeDeclarationResolver.Convert(vs); } } } else { // Explicitly don't resolve the methods' return types - it'll be done after filtering to e.g. resolve template types to the deduced one var optBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; if (call.PostfixForeExpression is TokenExpression) { baseExpression = GetResolvedConstructorOverloads((TokenExpression)call.PostfixForeExpression, ctxt); } else if (eval) { if (call.PostfixForeExpression is TemplateInstanceExpression) { baseValue = E(tix = call.PostfixForeExpression as TemplateInstanceExpression, false) as ISymbolValue; } else if (call.PostfixForeExpression is IdentifierExpression) { baseValue = E((IdentifierExpression)call.PostfixForeExpression, false) as ISymbolValue; } else { baseValue = E(call.PostfixForeExpression) as ISymbolValue; } if (baseValue is InternalOverloadValue) { baseExpression = ((InternalOverloadValue)baseValue).Overloads; } else if (baseValue != null) { baseExpression = new[] { baseValue.RepresentedType } } ; else { baseExpression = null; } } else { if (call.PostfixForeExpression is TemplateInstanceExpression) { baseExpression = GetOverloads(tix = (TemplateInstanceExpression)call.PostfixForeExpression, null, false); } else if (call.PostfixForeExpression is IdentifierExpression) { baseExpression = GetOverloads((IdentifierExpression)call.PostfixForeExpression, false); } else { baseExpression = new[] { AbstractType.Get(E(call.PostfixForeExpression)) } }; } ctxt.CurrentContext.ContextDependentOptions = optBackup; } }
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; } } 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 : baseExpression[0]); 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.EvalAndFilterOverloads( 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=TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if (returnBaseTypeOnly) argTypeFilteredOverloads.Add(bt); else argTypeFilteredOverloads.Add(new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes)); } 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; } }
void GetRawCallOverloads(ResolutionContext ctxt, PostfixExpression_MethodCall call, out AbstractType[] baseExpression, out ISymbolValue baseValue, out TemplateInstanceExpression tix) { baseValue = null; tix = null; if (call.PostfixForeExpression is PostfixExpression_Access) { var pac = (PostfixExpression_Access)call.PostfixForeExpression; tix = pac.AccessExpression as TemplateInstanceExpression; var vs = EvalPostfixAccessExpression(this, ctxt, pac, null, false, false); baseExpression = TypeDeclarationResolver.Convert(vs); } else { // Explicitly don't resolve the methods' return types - it'll be done after filtering to e.g. resolve template types to the deduced one var optBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; if (call.PostfixForeExpression is TokenExpression) { baseExpression = ExpressionTypeEvaluation.GetResolvedConstructorOverloads((TokenExpression)call.PostfixForeExpression, ctxt); } else { var fore = call.PostfixForeExpression; if (fore is TemplateInstanceExpression) { ImplicitlyExecute = false; tix = call.PostfixForeExpression as TemplateInstanceExpression; } else if (fore is IdentifierExpression) { ImplicitlyExecute = false; } if (call.PostfixForeExpression != null) { baseValue = call.PostfixForeExpression.Accept(this) as ISymbolValue; } if (baseValue is InternalOverloadValue) { baseExpression = ((InternalOverloadValue)baseValue).Overloads; } else if (baseValue != null) { baseExpression = new[] { baseValue.RepresentedType } } ; else { baseExpression = null; } } ctxt.CurrentContext.ContextDependentOptions = optBackup; } }
IExpression PrimaryExpression(IBlockNode Scope=null) { bool isModuleScoped = laKind == Dot; if (isModuleScoped) { Step(); if (IsEOF) { var dot = new TokenExpression(Dot) { Location = t.Location, EndLocation = t.EndLocation }; return new PostfixExpression_Access{ PostfixForeExpression = dot, AccessExpression = new TokenExpression(DTokens.Incomplete) }; } } // TemplateInstance if (IsTemplateInstance) { var tix = TemplateInstance(Scope); if (tix != null) tix.ModuleScoped = isModuleScoped; return tix; } if (IsLambaExpression()) return LambaExpression(Scope); CodeLocation startLoc; switch (laKind) { // ArrayLiteral | AssocArrayLiteral case OpenSquareBracket: return ArrayLiteral(Scope); case New: return NewExpression(Scope); case Typeof: return new TypeDeclarationExpression(TypeOf(Scope)); case __traits: return TraitsExpression(Scope); // Dollar (== Array length expression) case Dollar: Step(); return new TokenExpression(t.Kind) { Location = t.Location, EndLocation = t.EndLocation }; case Identifier: Step(); return new IdentifierExpression(t.Value) { Location = t.Location, EndLocation = t.EndLocation, ModuleScoped = isModuleScoped }; // SpecialTokens (this,super,null,true,false,$) // $ has been handled before case This: case Super: case Null: case True: case False: Step(); return new TokenExpression(t.Kind) { Location = t.Location, EndLocation = t.EndLocation }; case OpenParenthesis: if (IsFunctionLiteral()) goto case Function; // ( Expression ) Step(); var ret = new SurroundingParenthesesExpression() {Location=t.Location }; ret.Expression = Expression(); Expect(CloseParenthesis); ret.EndLocation = t.EndLocation; return ret; case Literal: Step(); startLoc = t.Location; // Concatenate multiple string literals here if (t.LiteralFormat == LiteralFormat.StringLiteral || t.LiteralFormat == LiteralFormat.VerbatimStringLiteral) { var sb = new StringBuilder(t.RawCodeRepresentation ?? t.Value); while (la.LiteralFormat == LiteralFormat.StringLiteral || la.LiteralFormat == LiteralFormat.VerbatimStringLiteral) { Step(); sb.Append(t.RawCodeRepresentation ?? t.Value); } return new IdentifierExpression(sb.ToString(), t.LiteralFormat, t.Subformat) { Location = startLoc, EndLocation = t.EndLocation }; } //else if (t.LiteralFormat == LiteralFormat.CharLiteral)return new IdentifierExpression(t.LiteralValue) { LiteralFormat=t.LiteralFormat,Location = startLoc, EndLocation = t.EndLocation }; return new IdentifierExpression(t.LiteralValue, t.LiteralFormat, t.Subformat, t.RawCodeRepresentation) { Location = startLoc, EndLocation = t.EndLocation }; // FunctionLiteral case Delegate: case Function: case OpenCurlyBrace: var fl = new FunctionLiteral() { Location=la.Location}; fl.AnonymousMethod.Location = la.Location; if (laKind == Delegate || laKind == Function) { Step(); fl.LiteralToken = t.Kind; } // file.d:1248 /* listdir (".", delegate bool (DirEntry * de) { auto s = std.string.format("%s : c %s, w %s, a %s", de.name, toUTCString (de.creationTime), toUTCString (de.lastWriteTime), toUTCString (de.lastAccessTime)); return true; } ); */ if (laKind != OpenCurlyBrace) // foo( 1, {bar();} ); -> is a legal delegate { if (!IsFunctionAttribute && Lexer.CurrentPeekToken.Kind == OpenParenthesis) fl.AnonymousMethod.Type = BasicType(Scope); else if (laKind != OpenParenthesis && laKind != OpenCurlyBrace) fl.AnonymousMethod.Type = Type(Scope); if (laKind == OpenParenthesis) Parameters(fl.AnonymousMethod); FunctionAttributes(fl.AnonymousMethod); } FunctionBody(fl.AnonymousMethod); if(IsEOF) fl.AnonymousMethod.EndLocation = CodeLocation.Empty; fl.EndLocation = fl.AnonymousMethod.EndLocation; if (Scope != null && !AllowWeakTypeParsing) // HACK -- not only on AllowWeakTypeParsing! But apparently, this stuff may be parsed twice, so force-skip results of the first attempt although this is a rather stupid solution Scope.Add(fl.AnonymousMethod); return fl; // AssertExpression case Assert: Step(); startLoc = t.Location; Expect(OpenParenthesis); var ce = new AssertExpression() { Location=startLoc}; var exprs = new List<IExpression>(); var assertedExpr = AssignExpression(Scope); if(assertedExpr!=null) exprs.Add(assertedExpr); if (laKind == (Comma)) { Step(); assertedExpr = AssignExpression(Scope); if (assertedExpr != null) exprs.Add(assertedExpr); } ce.AssignExpressions = exprs.ToArray(); Expect(CloseParenthesis); ce.EndLocation = t.EndLocation; return ce; // MixinExpression case Mixin: Step(); var me = new MixinExpression() { Location=t.Location}; if (Expect(OpenParenthesis)) { me.AssignExpression = AssignExpression(Scope); Expect(CloseParenthesis); } me.EndLocation = t.EndLocation; return me; // ImportExpression case Import: Step(); var ie = new ImportExpression() { Location=t.Location}; Expect(OpenParenthesis); ie.AssignExpression = AssignExpression(Scope); Expect(CloseParenthesis); ie.EndLocation = t.EndLocation; return ie; // TypeidExpression case Typeid: Step(); var tide = new TypeidExpression() { Location=t.Location}; Expect(OpenParenthesis); if (IsAssignExpression()) tide.Expression = AssignExpression(Scope); else { Lexer.PushLookAheadBackup(); AllowWeakTypeParsing = true; tide.Type = Type(Scope); AllowWeakTypeParsing = false; if (tide.Type == null || laKind != CloseParenthesis) { Lexer.RestoreLookAheadBackup(); tide.Expression = AssignExpression(Scope); } else Lexer.PopLookAheadBackup(); } Expect (CloseParenthesis); tide.EndLocation = t.EndLocation; return tide; // IsExpression case Is: Step (); var ise = new IsExpression () { Location = t.Location }; Expect (OpenParenthesis); if (laKind == DTokens.This && Lexer.CurrentPeekToken.Kind != DTokens.Dot) { Step (); ise.TestedType = new DTokenDeclaration (DTokens.This) { Location = t.Location, EndLocation = t.EndLocation }; } else ise.TestedType = Type (Scope); if (ise.TestedType == null) SynErr(laKind, "In an IsExpression, either a type or an expression is required!"); if (ise.TestedType != null) { if (laKind == Identifier && (Lexer.CurrentPeekToken.Kind == CloseParenthesis || Lexer.CurrentPeekToken.Kind == Equal || Lexer.CurrentPeekToken.Kind == Colon)) { Step(); Strings.Add(strVal); ise.TypeAliasIdentifierHash = strVal.GetHashCode(); ise.TypeAliasIdLocation = t.Location; } else if (IsEOF) ise.TypeAliasIdentifierHash = DTokens.IncompleteIdHash; } if (laKind == Colon || laKind == Equal) { Step(); ise.EqualityTest = t.Kind == Equal; } else if (laKind == CloseParenthesis) { Step(); ise.EndLocation = t.EndLocation; return ise; } /* TypeSpecialization: Type struct union class interface enum function delegate super const immutable inout shared return */ bool specialTest = false; if (ise.EqualityTest) { switch (laKind) { case Typedef: // typedef is possible although it's not yet documented in the syntax docs case Enum: case Delegate: case Function: case Super: case Return: specialTest = true; break; case Const: case Immutable: case InOut: case Shared: specialTest = Peek(1).Kind == CloseParenthesis || Lexer.CurrentPeekToken.Kind == Comma; break; default: specialTest = IsClassLike(laKind); break; } } if (specialTest) { Step(); ise.TypeSpecializationToken = t.Kind; } else if (IsEOF) ise.TypeSpecializationToken = DTokens.Incomplete; else ise.TypeSpecialization = Type(Scope); // TemplateParameterList if (laKind == Comma) { var tempParam = new List<TemplateParameter>(); do { Step(); tempParam.Add(TemplateParameter(Scope as DNode)); } while (laKind == Comma); ise.TemplateParameterList = tempParam.ToArray(); } Expect(CloseParenthesis); ise.EndLocation = t.EndLocation; return ise; default: if (DTokens.IsMetaIdentifier(laKind)) goto case Dollar; else if (IsBasicType()) { startLoc = la.Location; var bt=BasicType(Scope); switch (laKind) { case DTokens.Dot: // BasicType . Identifier Step(); // Things like incomplete 'float.' expressions shall be parseable, too if (Expect(Identifier) || IsEOF) return new PostfixExpression_Access() { PostfixForeExpression = new TypeDeclarationExpression(bt), AccessExpression = IsEOF ? new TokenExpression(Incomplete) as IExpression : new IdentifierExpression(t.Value) { Location = t.Location, EndLocation = t.EndLocation }, EndLocation = t.EndLocation }; break; case DTokens.OpenParenthesis: Step(); var callExp = new PostfixExpression_MethodCall { PostfixForeExpression = new TypeDeclarationExpression(bt) }; callExp.Arguments = ArgumentList(Scope).ToArray(); Expect(DTokens.CloseParenthesis); return callExp; default: if (bt is TypeOfDeclaration || bt is MemberFunctionAttributeDecl) return new TypeDeclarationExpression(bt); break; } return null; } SynErr(Identifier); if(laKind != CloseCurlyBrace) Step(); if (IsEOF) return new TokenExpression (DTokens.Incomplete) { Location = t.Location, EndLocation = t.Location }; // Don't know why, in rare situations, t tends to be null.. if (t == null) return null; return new TokenExpression() { Location = t.Location, EndLocation = t.EndLocation }; } }
public override void Visit(PostfixExpression_MethodCall x) { CallExpressionStack.Push (x); base.Visit (x); CallExpressionStack.Pop (); }
public void opDispatch() { var ctxt = CreateCtxt ("A", @"module A; class S { int* opDispatch(string s)(int i){ } int opDispatch(string s)(){ } } struct S2 { T opDispatch(string s, T)(T i){ return i; } } struct S3 { static int opDispatch(string s)(){ } } struct D { template opDispatch(string s) { enum int opDispatch = 8; } } S s; S2 s2; S3 s3; void main() { S2 loc; x; }"); AbstractType t; DSymbol ds; IExpression x; ITypeDeclaration td; ISymbolValue v; var main = ctxt.ParseCache [0] ["A"] ["main"].First () as DMethod; var stmt_x = main.Body.SubStatements.ElementAt (1); x = new PostfixExpression_MethodCall{ Arguments = new[]{ new IdentifierExpression(123m, LiteralFormat.Scalar) }, PostfixForeExpression = new PostfixExpression_Access{ AccessExpression = new IdentifierExpression("bar"), PostfixForeExpression = new IdentifierExpression("loc") { Location = stmt_x.Location } } }; ctxt.PushNewScope (main, stmt_x); ds = Evaluation.EvaluateType (x, ctxt) as DSymbol; Assert.That (ds, Is.TypeOf(typeof(TemplateParameterSymbol))); Assert.That (ds.Base, Is.TypeOf(typeof(PrimitiveType))); ctxt.Pop (); x = DParser.ParseExpression ("s2.bar(s)"); ds = Evaluation.EvaluateType (x, ctxt) as DSymbol; Assert.That (ds, Is.TypeOf (typeof(TemplateParameterSymbol))); Assert.That (ds.Base, Is.TypeOf(typeof(ClassType))); x = DParser.ParseExpression ("s.foo(123)"); t = Evaluation.EvaluateType (x, ctxt); Assert.That (t, Is.TypeOf(typeof(PointerType))); x = DParser.ParseExpression ("s.foo"); ds = Evaluation.EvaluateType (x, ctxt) as DSymbol; Assert.That (ds, Is.TypeOf(typeof(MemberSymbol))); Assert.That (ds.Base, Is.TypeOf(typeof(PrimitiveType))); x = DParser.ParseExpression ("D.foo"); ds = Evaluation.EvaluateType (x, ctxt) as DSymbol; Assert.That (ds, Is.TypeOf(typeof(MemberSymbol))); Assert.That (ds.Base, Is.TypeOf(typeof(PrimitiveType))); v = Evaluation.EvaluateValue (x, ctxt); Assert.That (v, Is.TypeOf(typeof(PrimitiveValue))); Assert.That ((v as PrimitiveValue).Value, Is.EqualTo(8m)); td = DParser.ParseBasicType("D.foo"); ds = TypeDeclarationResolver.ResolveSingle (td, ctxt) as DSymbol; Assert.That (ds, Is.TypeOf(typeof(MemberSymbol))); Assert.That (ds.Base , Is.TypeOf(typeof(PrimitiveType))); }
public override void Visit(PostfixExpression_MethodCall x) { if (triggerChar == '(' && x.ArgumentCount > 0 && IsIncompleteExpression(x.Arguments[x.ArgumentCount - 1])) { halt = true; explicitlyNoCompletion = true; } else base.Visit(x); }
public static AbstractType EvalMethodCall(AbstractType[] baseExpression, ISymbolValue baseValue, TemplateInstanceExpression tix, ResolutionContext ctxt, PostfixExpression_MethodCall call, out List <ISemantic> callArguments, out ISymbolValue delegateValue, bool returnBaseTypeOnly, AbstractSymbolValueProvider ValueProvider = null) { //TODO: Refactor this crap! delegateValue = null; callArguments = null; 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 = baseExpression; var nextResults = new List <AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is AmbiguousType) { nextResults.AddRange((b as AmbiguousType).Overloads); } else if (b is TemplateParameterSymbol) { nextResults.Add((b as TemplateParameterSymbol).Base); } else 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 (ValueProvider != null) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else { ValueProvider.LogError(call, "Variable must be a delegate, not anything else"); return(null); } } else { var bt = mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt); // Must be of type delegate if (bt is DelegateType) { var ret = HandleCallDelegateType(ValueProvider, bt as DelegateType, methodOverloads, returnBaseTypeOnly); if (ret is ISymbolValue) { delegateValue = ret as ISymbolValue; return(null); } else if (ret is AbstractType) { return(ret as AbstractType); } } 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 ret = HandleCallDelegateType(ValueProvider, b as DelegateType, methodOverloads, returnBaseTypeOnly); if (ret is ISymbolValue) { delegateValue = ret as ISymbolValue; return(null); } else if (ret is AbstractType) { return(ret as AbstractType); } } else if (b is ClassType || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) { continue; } foreach (var i in ExpressionTypeEvaluation.GetOpCalls(tit, requireStaticItems)) { 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! */ 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) { methodOverloads.Add(b); } else if (b is PrimitiveType) // dmd 2.066: Uniform Construction Syntax. creal(3) is of type creal. { methodOverloads.Add(b); } } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) { return(null); } // Get all arguments' types callArguments = new List <ISemantic>(); if (call.Arguments != null) { if (ValueProvider != null) { foreach (var arg in call.Arguments) { callArguments.Add(arg != null ? Evaluation.EvaluateValue(arg, ValueProvider) : null); } } else { foreach (var arg in call.Arguments) { callArguments.Add(arg != null ? ExpressionTypeEvaluation.EvaluateType(arg, ctxt) : null); } } } #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt); methodOverloads.Clear(); if (deducedOverloads != null) { methodOverloads.AddRange(deducedOverloads); } } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); bool hasHandledUfcsResultBefore = false; AbstractType untemplatedMethodResult = null; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { HandleDMethodOverload(ctxt, ValueProvider != null, baseValue, callArguments, returnBaseTypeOnly, argTypeFilteredOverloads, ref hasHandledUfcsResultBefore, ov as MemberSymbol, ref untemplatedMethodResult); } else if (ov is DelegateType) { var dg = ov as DelegateType; var bt = dg.Base ?? TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { if (dg.Base == null) { if (dg.IsFunctionLiteral) { dg = new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters); } else { dg = new DelegateType(bt, dg.DeclarationOrExpressionBase as DelegateDeclaration, dg.Parameters); } } argTypeFilteredOverloads.Add(new DelegateCallSymbol(dg, call)); } } else if (ov is PrimitiveType) // dmd 2.066: Uniform Construction Syntax. creal(3) is of type creal. { if (ValueProvider != null) { if (callArguments == null || callArguments.Count != 1) { ValueProvider.LogError(call, "Uniform construction syntax expects exactly one argument"); } else { var pv = callArguments[0] as PrimitiveValue; if (pv == null) { ValueProvider.LogError(call, "Uniform construction syntax expects one built-in scalar value as first argument"); } else { delegateValue = new PrimitiveValue(pv.Value, ov as PrimitiveType, pv.ImaginaryPart); } } } argTypeFilteredOverloads.Add(ov); } } // Prefer untemplated methods over templated ones if (untemplatedMethodResult != null) { return(untemplatedMethodResult); } #endregion return(AmbiguousType.Get(argTypeFilteredOverloads, tix)); }
ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly=true) { // Deduce template parameters later on AbstractType[] baseExpression; ISymbolValue baseValue; TemplateInstanceExpression tix; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix); 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{ EvalError(call, "Variable must be a delegate, not anything else", mr); return null; } } 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) { EvalError(call, "TODO", dg); return null; } //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 || b is StructType) { var tit = (TemplateIntermediateType)b; /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = tit.Definition; if (classDef == null) continue; foreach (var i in GetOpCalls(tit, requireStaticItems)) 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! */ 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) 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>(); bool hasNonFinalArgs = false; if (call.Arguments != null) foreach (var arg in call.Arguments) callArguments.Add(E(arg)); #region If explicit template type args were given, try to associate them with each overload if (tix != null) { var args = TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt, out hasNonFinalArgs); var deducedOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads(methodOverloads, args, true, ctxt, hasNonFinalArgs); methodOverloads.Clear(); if(deducedOverloads != null) methodOverloads.AddRange(deducedOverloads); } #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List<AbstractType>(); bool hasHandledUfcsResultBefore = false; foreach (var ov in methodOverloads) { if (ov is MemberSymbol) { var ms = ov as MemberSymbol; var dm = ms.Definition as DMethod; if (dm != null) { // In the case of an ufcs, insert the first argument into the CallArguments list if (ms.IsUFCSResult && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : ((MemberSymbol)baseExpression[0]).FirstArgument); hasHandledUfcsResultBefore = true; } else if (!ms.IsUFCSResult && 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; } var deducedTypeDict = new DeducedTypeDictionary(ms); var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); if(dm.Parameters.Count == 0 && callArguments.Count > 0) continue; int currentArg = 0; bool add = true; if (dm.Parameters.Count > 0 || callArguments.Count > 0) 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 && TryHandleMethodArgumentTuple(ref add, callArguments, dm, deducedTypeDict, i, ref currentArg)) continue; else if (currentArg < callArguments.Count) { if (!templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++])) { add = false; break; } } else { // If there are more parameters than arguments given, check if the param has default values if (!(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer == null) { add = false; break; } // Assume that all further method parameters do have default values - and don't check further parameters break; } } // If type params were unassigned, try to take the defaults if (add && dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar.NameHash] == null) { add = templateParamDeduction.Handle(tpar, null); if (!add) { if (hasNonFinalArgs) { deducedTypeDict[tpar] = new TemplateParameterSymbol(tpar, null); add = true; } else break; } } } } if (add && (deducedTypeDict.AllParamatersSatisfied || hasNonFinalArgs)) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); var pop = ctxt.ScopedBlock != dm; if(pop) ctxt.PushNewScope(dm); ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); var bt=ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if(pop) ctxt.Pop(); else ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); if(eval || !returnBaseTypeOnly) argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); else argTypeFilteredOverloads.Add(bt); } } } else if(ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (!eval || 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.Count != 0 ? argTypeFilteredOverloads[0] : null; } }
void GetRawCallOverloads(PostfixExpression_MethodCall call, out AbstractType[] baseExpression, out ISymbolValue baseValue, out TemplateInstanceExpression tix) { baseExpression = null; baseValue = null; tix = null; if (call.PostfixForeExpression is PostfixExpression_Access) { var pac = (PostfixExpression_Access)call.PostfixForeExpression; tix = pac.AccessExpression as TemplateInstanceExpression; var vs = E(pac, null, false, false); if (vs != null && vs.Length != 0) { if (vs[0] is ISymbolValue) { baseValue = (ISymbolValue)vs[0]; baseExpression = new[] { baseValue.RepresentedType }; } else if (vs[0] is InternalOverloadValue) baseExpression = ((InternalOverloadValue)vs[0]).Overloads; else baseExpression = TypeDeclarationResolver.Convert(vs); } } else { // Explicitly don't resolve the methods' return types - it'll be done after filtering to e.g. resolve template types to the deduced one var optBackup = ctxt.CurrentContext.ContextDependentOptions; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; if (call.PostfixForeExpression is TokenExpression) baseExpression = GetResolvedConstructorOverloads((TokenExpression)call.PostfixForeExpression, ctxt); else if (eval) { if (call.PostfixForeExpression is TemplateInstanceExpression) baseValue = E(tix = call.PostfixForeExpression as TemplateInstanceExpression, false) as ISymbolValue; else if (call.PostfixForeExpression is IdentifierExpression) baseValue = E((IdentifierExpression)call.PostfixForeExpression, false) as ISymbolValue; else baseValue = E(call.PostfixForeExpression) as ISymbolValue; if (baseValue is InternalOverloadValue) baseExpression = ((InternalOverloadValue)baseValue).Overloads; else if (baseValue != null) baseExpression = new[] { baseValue.RepresentedType }; else baseExpression = null; } else { if (call.PostfixForeExpression is TemplateInstanceExpression) baseExpression = GetOverloads(tix = (TemplateInstanceExpression)call.PostfixForeExpression, null, false); else if (call.PostfixForeExpression is IdentifierExpression) baseExpression = GetOverloads(call.PostfixForeExpression as IdentifierExpression, deduceParameters:false); else baseExpression = new[] { AbstractType.Get(E(call.PostfixForeExpression)) }; } ctxt.CurrentContext.ContextDependentOptions = optBackup; } }
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); } }