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)); }
public ISymbolValue Visit(TraitsExpression te) { switch (te.Keyword) { case "": case null: return(null); case "hasMember": bool ret = false; var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; AbstractType t; var pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if (pfa != null && t != null) { t.NonStaticAccess = true; ignoreErrors = true; var res = ExpressionTypeEvaluation.EvaluateType(pfa, ctxt, false); ret = res != null; ignoreErrors = false; } ctxt.ContextIndependentOptions = optionsBackup; return(new PrimitiveValue(ret, te)); case "identifier": if (te.Arguments != null && te.Arguments.Length == 1) { return(new ArrayValue(GetStringType(), te.Arguments[0].ToString())); } break; case "getMember": pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if (pfa == null || t == null) { break; } var vs = EvalPostfixAccessExpression(this, ctxt, pfa, t, ValueProvider: ValueProvider); if (vs == null || vs.Length == 0) { return(null); } return(vs[0]); case "getOverloads": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if (pfa != null && t != null) { vs = EvalPostfixAccessExpression(this, ctxt, pfa, t); } else { vs = null; } ctxt.ContextIndependentOptions = optionsBackup; return(new TypeValue(new DTuple(te, vs))); case "getProtection": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; var prot = "public"; if (te.Arguments == null || te.Arguments.Length != 1 || te.Arguments[0] == null) { EvalError(te, "First trait argument must be a symbol identifier"); } else { t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[0]); if (t is DSymbol) { var dn = (t as DSymbol).Definition; if (dn.ContainsAttribute(DTokens.Private)) { prot = "private"; } else if (dn.ContainsAttribute(DTokens.Protected)) { prot = "protected"; } else if (dn.ContainsAttribute(DTokens.Package)) { prot = "package"; } else if (dn.ContainsAttribute(DTokens.Export)) { prot = "export"; } } else { EvalError(te, "First argument must evaluate to an existing code symbol"); } } ctxt.ContextIndependentOptions = optionsBackup; return(new ArrayValue(GetStringType(), prot)); case "getVirtualFunctions": break; case "getVirtualMethods": break; case "parent": break; case "classInstanceSize": break; case "allMembers": break; case "derivedMembers": break; case "isSame": ret = false; if (te.Arguments == null || te.Arguments.Length < 2) { EvalError(te, "isSame requires two arguments to compare"); } else { t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[0]); if (t != null) { var t2 = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[1]); if (t2 != null) { ret = Resolver.ResultComparer.IsEqual(t, t2); } } } return(new PrimitiveValue(ret, te)); case "compiles": ret = false; if (te.Arguments != null) { foreach (var arg in te.Arguments) { ret = arg == null || ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, arg) != null; if (!ret) { break; } } } return(new PrimitiveValue(ret, te)); } #region isXYZ-traits if (te.Keyword.StartsWith("is")) { var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; bool ret = false; if (te.Arguments != null) { foreach (var arg in te.Arguments) { var t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, arg); bool tested = true; switch (te.Keyword) { case "isVirtualFunction": case "isVirtualMethod": var ms = t as MemberSymbol; if (ms == null || !(ms.Definition is DMethod)) { break; } var dm = ms.Definition as DMethod; var dc = dm.Parent as DClassLike; if (dc != null && dc.ClassType != DTokens.Struct) { bool includeFinalNonOverridingMethods = te.Keyword == "isVirtualFunction"; ret = !dm.ContainsAttribute(includeFinalNonOverridingMethods ? (byte)0 : DTokens.Final, DTokens.Static); } break; case "isAbstractFunction": ms = t as MemberSymbol; ret = ms != null && ms.Definition is DMethod && ms.Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalFunction": ms = t as MemberSymbol; if (ms != null && ms.Definition is DMethod) { ret = ms.Definition.ContainsAttribute(DTokens.Abstract) || (ms.Definition.Parent is DClassLike && (ms.Definition.Parent as DClassLike).ContainsAttribute(DTokens.Final)); } break; case "isStaticFunction": ms = t as MemberSymbol; ret = ms != null && ms.Definition is DMethod && ms.Definition.IsStatic; break; case "isRef": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Ref); break; case "isOut": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Out); break; case "isLazy": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Lazy); break; default: tested = false; break; } t = DResolver.StripMemberSymbols(t); if (!tested) { switch (te.Keyword) { case "isArithmetic": var pt = t as PrimitiveType; ret = pt != null && ( DTokens.IsBasicType_Integral(pt.TypeToken) || DTokens.IsBasicType_FloatingPoint(pt.TypeToken)); break; case "isFloating": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_FloatingPoint(pt.TypeToken); break; case "isIntegral": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_Integral(pt.TypeToken); break; case "isScalar": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType(pt.TypeToken); break; case "isUnsigned": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_Unsigned(pt.TypeToken); break; case "isAbstractClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Final); break; case "isAssociativeArray": ret = t is AssocArrayType && !(t is ArrayType); break; case "isStaticArray": ret = t is ArrayType && (t as ArrayType).IsStaticArray; break; } } if (!ret) { break; } } } ctxt.ContextIndependentOptions = optionsBackup; return(new PrimitiveValue(ret, te)); } else { EvalError(te, "Illegal trait token"); return(null); } #endregion }
public ISymbolValue Visit(NewExpression nex) { //TODO: Create virtual object and call the appropriate ctor, then return the object return(TryDoCTFEOrGetValueRefs(ExpressionTypeEvaluation.EvaluateType(nex, ctxt, false), nex)); }
public ISymbolValue Visit(IdentifierExpression id) { var ImplicitlyExecute = this.ImplicitlyExecute; this.ImplicitlyExecute = true; if (id.IsIdentifier) { var o = ExpressionTypeEvaluation.EvaluateType(id, ctxt, false); if (o == null) { EvalError(id, "Symbol could not be found"); return(null); } return(TryDoCTFEOrGetValueRefs(o, id, ImplicitlyExecute)); } byte tt; switch (id.Format) { case Parser.LiteralFormat.CharLiteral: var tk = id.Subformat == LiteralSubformat.Utf32 ? DTokens.Dchar : id.Subformat == LiteralSubformat.Utf16 ? DTokens.Wchar : DTokens.Char; return(new PrimitiveValue(tk, Convert.ToDecimal((int)(char)id.Value), id)); case LiteralFormat.FloatingPoint | LiteralFormat.Scalar: var im = id.Subformat.HasFlag(LiteralSubformat.Imaginary); tt = im ? DTokens.Idouble : DTokens.Double; if (id.Subformat.HasFlag(LiteralSubformat.Float)) { tt = im ? DTokens.Ifloat : DTokens.Float; } else if (id.Subformat.HasFlag(LiteralSubformat.Real)) { tt = im ? DTokens.Ireal : DTokens.Real; } var v = Convert.ToDecimal(id.Value); return(new PrimitiveValue(tt, im ? 0 : v, id, im ? v : 0)); case LiteralFormat.Scalar: var unsigned = id.Subformat.HasFlag(LiteralSubformat.Unsigned); if (id.Subformat.HasFlag(LiteralSubformat.Long)) { tt = unsigned ? DTokens.Ulong : DTokens.Long; } else { tt = unsigned ? DTokens.Uint : DTokens.Int; } return(new PrimitiveValue(tt, Convert.ToDecimal(id.Value), id)); case Parser.LiteralFormat.StringLiteral: case Parser.LiteralFormat.VerbatimStringLiteral: return(new ArrayValue(GetStringType(id.Subformat), id)); default: return(null); } }