public ISymbolValue Visit(TemplateInstanceExpression tix) { var ImplicitlyExecute = this.ImplicitlyExecute; this.ImplicitlyExecute = true; return(TryDoCTFEOrGetValueRefs(AmbiguousType.Get(ExpressionTypeEvaluation.GetOverloads(tix, ctxt), tix), tix, ImplicitlyExecute)); }
public ISymbolValue Visit(TemplateInstanceExpression tix) { var ImplicitlyExecute = this.ImplicitlyExecute; this.ImplicitlyExecute = true; var o = DResolver.StripAliasSymbols(ExpressionTypeEvaluation.GetOverloads(tix, ctxt)); return(TryDoCTFEOrGetValueRefs(o, tix, ImplicitlyExecute)); }
public static AbstractType EvaluateType(IExpression x, ResolutionContext ctxt) { var ev = new ExpressionTypeEvaluation(ctxt); if (!Debugger.IsAttached) { try { return(x.Accept(ev)); } catch { return(null); } } else { return(x.Accept(ev)); } }
void GetRawCallOverloads(ResolutionContext ctxt, IExpression callForeExpression, out AbstractType[] baseExpression, out TemplateInstanceExpression tix) { tix = null; if (callForeExpression is PostfixExpression_Access) { var pac = (PostfixExpression_Access)callForeExpression; 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 (callForeExpression is TokenExpression) { baseExpression = ExpressionTypeEvaluation.GetResolvedConstructorOverloads((TokenExpression)callForeExpression, ctxt); } else { if (callForeExpression is TemplateInstanceExpression) { baseExpression = ExpressionTypeEvaluation.GetOverloads(tix = (TemplateInstanceExpression)callForeExpression, ctxt, null, false); } else if (callForeExpression is IdentifierExpression) { baseExpression = ExpressionTypeEvaluation.GetOverloads(callForeExpression as IdentifierExpression, ctxt, deduceParameters: false); } else { baseExpression = new[] { callForeExpression != null?AbstractType.Get(callForeExpression.Accept(this)) : null } }; } ctxt.CurrentContext.ContextDependentOptions = optBackup; } }
/// <summary> /// Since most expressions should return a single type only, it's not needed to use this function unless you might /// want to pay attention on (illegal) multiple overloads. /// </summary> public static AbstractType[] EvaluateTypes(IExpression x, ResolutionContext ctxt) { var ev = new ExpressionTypeEvaluation(ctxt); AbstractType t; if (!Debugger.IsAttached) { try { t = x.Accept(ev); } catch { t = null; } } else { t = x.Accept(ev); } if (t is AmbiguousType) { return(((AmbiguousType)t).Overloads); } return(t == null ? null : new[] { t }); }
/// <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> public static R[] EvalPostfixAccessExpression <R>(ExpressionVisitor <R> vis, ResolutionContext ctxt, PostfixExpression_Access acc, ISemantic resultBase = null, bool EvalAndFilterOverloads = true, bool ResolveImmediateBaseType = true, AbstractSymbolValueProvider ValueProvider = null) where R : class, ISemantic { if (acc == null) { return(null); } var baseExpression = resultBase ?? (acc.PostfixForeExpression != null ? acc.PostfixForeExpression.Accept(vis) as ISemantic : null); 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 = ExpressionTypeEvaluation.GetOverloads(tix, ctxt, new[] { AbstractType.Get(baseExpression) }, EvalAndFilterOverloads); if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions = optBackup; } } else if (acc.AccessExpression is IdentifierExpression) { var id = acc.AccessExpression as IdentifierExpression; if (ValueProvider != null && EvalAndFilterOverloads && baseExpression != null) { var staticPropResult = StaticProperties.TryEvalPropertyValue(ValueProvider, baseExpression, id.ValueStringHash); if (staticPropResult != null) { return new[] { (R)staticPropResult } } ; } if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; } overloads = ExpressionTypeEvaluation.GetOverloads(id, ctxt, AmbiguousType.TryDissolve(AbstractType.Get(baseExpression)), EvalAndFilterOverloads); 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); } // If evaluation active and the access expression is stand-alone, return a single item only. if (EvalAndFilterOverloads && ValueProvider != null) { return new[] { (R) new Evaluation(ValueProvider).TryDoCTFEOrGetValueRefs(AmbiguousType.Get(overloads, acc.AccessExpression), acc.AccessExpression) } } ; return(overloads as R[]); } ISymbolValue EvalForeExpression(PostfixExpression ex) { return(ex.PostfixForeExpression != null?ex.PostfixForeExpression.Accept(this) : 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; } }
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(IdentifierExpression id) { var ImplicitlyExecute = this.ImplicitlyExecute; this.ImplicitlyExecute = true; if (id.IsIdentifier) { var o = ExpressionTypeEvaluation.EvaluateTypes(id, ctxt); if (o == null || o.Length == 0) { 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); } }
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(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) { ignoreErrors = true; ret = EvalPostfixAccessExpression(this, ctxt, pfa, t, false) != 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; 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 }