public IEnumerable <DMethod> FindFitting(ResolverContextStack ctxt, CodeLocation currentLocation, ISemantic firstArgument, string nameFilter = null) { if (IsProcessing) { return(null); } var preMatchList = new List <DMethod>(); bool dontUseNameFilter = nameFilter == null; lock (CachedMethods) foreach (var kv in CachedMethods) { // First test if arg is matching the parameter if ((dontUseNameFilter || kv.Key.Name == nameFilter) && ResultComparer.IsImplicitlyConvertible(firstArgument, kv.Value, ctxt)) { preMatchList.Add(kv.Key); } } // Then filter out methods which cannot be accessed in the current context // (like when the method is defined in a module that has not been imported) var mv = new MatchFilterVisitor <DMethod>(ctxt, preMatchList); mv.IterateThroughScopeLayers(currentLocation); return(mv.filteredList); }
bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r) { // Bottom-level reached if (id.InnerDeclaration == null && Contains(id.IdHash) && !id.ModuleScoped) { // Associate template param with r return(Set((p != null && id.IdHash == p.NameHash) ? p : null, r, id.IdHash)); } var deducee = DResolver.StripMemberSymbols(AbstractType.Get(r)) as DSymbol; if (id.InnerDeclaration != null && deducee != null && deducee.Definition.NameHash == id.IdHash) { var physicalParentType = TypeDeclarationResolver.HandleNodeMatch(deducee.Definition.Parent, ctxt, null, id.InnerDeclaration); if (HandleDecl(p, id.InnerDeclaration, physicalParentType)) { if (Contains(id.IdHash)) { Set((p != null && id.IdHash == p.NameHash) ? p : null, deducee, id.IdHash); } return(true); } } /* * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r */ var _r = TypeDeclarationResolver.ResolveSingle(id, ctxt); return(_r != null && (EnforceTypeEqualityWhenDeducing ? ResultComparer.IsEqual(r, _r) : ResultComparer.IsImplicitlyConvertible(r, _r))); }
void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null) { if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null) { var pop = ctxt.ScopedBlock != dm; if (pop) { ctxt.PushNewScope(dm); } var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters [0].Type, ctxt); if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt)) { var res = alreadyResolvedMethod ?? new MemberSymbol(dm, null, sr); res.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(res); } if (pop) { ctxt.Pop(); } } }
bool Handle(TemplateValueParameter p, ISemantic arg) { // Handle default arg case if (arg == null) { if (p.DefaultExpression != null) { var eval = Evaluation.EvaluateValue(p.DefaultExpression, ctxt); if (eval == null) { return(false); } return(Set(p, eval)); } else { return(false); } } var valueArgument = arg as ISymbolValue; // There must be a constant expression given! if (valueArgument == null) { return(false); } // Check for param type <-> arg expression type match var paramType = TypeDeclarationResolver.Resolve(p.Type, ctxt); if (paramType == null || paramType.Length == 0) { return(false); } if (valueArgument.RepresentedType == null || !ResultComparer.IsImplicitlyConvertible(paramType[0], valueArgument.RepresentedType)) { return(false); } // If spec given, test for equality (only ?) if (p.SpecializationExpression != null) { var specVal = Evaluation.EvaluateValue(p.SpecializationExpression, ctxt); if (specVal == null || !SymbolValueComparer.IsEqual(specVal, valueArgument)) { return(false); } } return(Set(p, arg)); }
bool HandleDecl(TypeOfDeclaration t, AbstractType r) { // Can I enter some template parameter referencing id into a typeof specialization!? // class Foo(T:typeof(1)) {} ? var t_res = TypeDeclarationResolver.Resolve(t, ctxt); if (t_res == null) { return(false); } return(ResultComparer.IsImplicitlyConvertible(r, t_res)); }
private bool evalIsExpression_NoAlias(IsExpression isExpression, AbstractType typeToCheck) { if (isExpression.TypeSpecialization != null) { var spec = DResolver.StripAliasSymbols(TypeDeclarationResolver.Resolve(isExpression.TypeSpecialization, ctxt)); return(spec != null && spec.Length != 0 && (isExpression.EqualityTest ? ResultComparer.IsEqual(typeToCheck, spec[0]) : ResultComparer.IsImplicitlyConvertible(typeToCheck, spec[0], ctxt))); } return(isExpression.EqualityTest && evalIsExpression_EvalSpecToken(isExpression, typeToCheck, false).Item1); }
protected override bool HandleItem(INode n) { AbstractType t; if (n is DMethod && (nameFilterHash == 0 || n.NameHash == nameFilterHash) && cache.TryGetValue(n as DMethod, out t) && ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt)) { filteredMethods.Add(n as DMethod); } return(false); }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { var oldV = vp[Variable]; if (oldV is ArrayValue) { var av = (ArrayValue)oldV; //TODO: Immutability checks if (av.IsString) { } else { var at = av.RepresentedType as ArrayType; var newElements = new ISymbolValue[av.Elements.Length + (ItemNumber < 0 ? 1:0)]; av.Elements.CopyTo(newElements, 0); if (!ResultComparer.IsImplicitlyConvertible(value.RepresentedType, at.ValueType)) { if (vp.ev != null) { vp.ev.EvalError(null, value.ToCode() + " must be implicitly convertible to the array's value type!", value); } return; } // Add.. if (ItemNumber < 0) { av.Elements[av.Elements.Length - 1] = value; } else // or set the new value { av.Elements[ItemNumber] = value; } vp[Variable] = new ArrayValue(at, newElements); } } else { if (vp.ev != null) { vp.ev.EvalError(null, "Type of accessed item must be an array", oldV); } } }
bool HandleDecl(VectorDeclaration v, AbstractType r) { if (r.DeclarationOrExpressionBase is VectorDeclaration) { var v_res = ExpressionTypeEvaluation.EvaluateType(v.Id, ctxt); var r_res = ExpressionTypeEvaluation.EvaluateType(((VectorDeclaration)r.DeclarationOrExpressionBase).Id, ctxt); if (v_res == null || r_res == null) { return(false); } else { return(ResultComparer.IsImplicitlyConvertible(r_res, v_res)); } } return(false); }
void HandleMethod(DMethod dm, MemberSymbol alreadyResolvedMethod = null) { if (dm != null && dm.Parameters.Count > 0 && dm.Parameters[0].Type != null) { var loc = dm.Body != null ? dm.Body.Location : dm.Location; using (alreadyResolvedMethod != null ? ctxt.Push(alreadyResolvedMethod, loc) : ctxt.Push(dm, loc)) { var t = TypeDeclarationResolver.ResolveSingle(dm.Parameters[0].Type, ctxt); if (ResultComparer.IsImplicitlyConvertible(firstArgument, t, ctxt)) { var res = alreadyResolvedMethod ?? TypeDeclarationResolver.HandleNodeMatch(dm, ctxt, typeBase: sr); res.Tag = new UfcsTag { firstArgument = firstArgument }; matches.Add(res); } } } }
bool HandleDecl(TemplateTypeParameter p, IdentifierDeclaration id, ISemantic r) { // Bottom-level reached if (id.InnerDeclaration == null && Contains(id.Id) && !id.ModuleScoped) { // Associate template param with r return(Set(p, r, id.Id)); } /* * If not stand-alone identifier or is not required as template param, resolve the id and compare it against r */ var _r = TypeDeclarationResolver.Resolve(id, ctxt); ctxt.CheckForSingleResult(_r, id); return(_r != null && _r.Length != 0 && (EnforceTypeEqualityWhenDeducing ? ResultComparer.IsEqual(r, _r[0]) : ResultComparer.IsImplicitlyConvertible(r, _r[0]))); }
internal static bool TryHandleMethodArgumentTuple(ResolutionContext ctxt, ref bool add, List <ISemantic> callArguments, DMethod dm, DeducedTypeDictionary deducedTypeDict, int currentParameter, ref int currentArg) { // .. so only check if it's an identifer & if the id represents a tuple parameter var id = dm.Parameters[currentParameter].Type as IdentifierDeclaration; var curNode = dm as DNode; TemplateParameter tpar = null; while (curNode != null && !curNode.TryGetTemplateParameter(id.IdHash, out tpar)) { curNode = curNode.Parent as DNode; } if (!(tpar is TemplateTupleParameter)) { return(false); } int lastArgumentToTake = -1; /* * Note: an expression tuple parameter can occur also somewhere in between the parameter list! * void write(A...)(bool b, A a, double d) {} * * can be matched by * write(true, 1.2) as well as * write(true, "asdf", 1.2) as well as * write(true, 123, true, 'c', [3,4,5], 3.4) ! */ TemplateParameterSymbol tps; DTuple tuple = null; if (deducedTypeDict.TryGetValue(tpar, out tps) && tps != null) { if (tps.Base is DTuple) { tuple = tps.Base as DTuple; lastArgumentToTake = currentParameter + (tuple.Items == null ? 0 : (tuple.Items.Length - 1)); } else { // Error: Type param must be tuple! } } // - Get the (amount of) arguments that shall be put into the tuple else if (currentParameter == dm.Parameters.Count - 1) { // The usual case: A tuple of a variable length is put at the end of a parameter list.. // take all arguments from i until the end of the argument list.. // ; Also accept empty tuples lastArgumentToTake = callArguments.Count - 1; } else { // Get the type of the next expected parameter var nextExpectedParameter = DResolver.StripMemberSymbols(TypeDeclarationResolver.ResolveSingle(dm.Parameters[currentParameter + 1].Type, ctxt)); // Look for the first argument whose type is equal to the next parameter's type.. for (int k = currentArg; k < callArguments.Count; k++) { if (ResultComparer.IsEqual(AbstractType.Get(callArguments[k]), nextExpectedParameter)) { // .. and assume the tuple to go from i to the previous argument.. lastArgumentToTake = k - 1; break; } } } int argCountToHandle = lastArgumentToTake - currentArg + 1; if (tuple != null) { // - If there's been set an explicit type tuple, compare all arguments' types with those in the tuple if (tuple.Items != null) { foreach (ISemantic item in tuple.Items) { if (currentArg >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[currentArg++], AbstractType.Get(item), ctxt)) { add = false; return(true); } } } } else { // - If there was no explicit initialization, put all arguments' types into a type tuple var argsToTake = new ISemantic[argCountToHandle]; callArguments.CopyTo(currentArg, argsToTake, 0, argsToTake.Length); currentArg += argsToTake.Length; var tt = new DTuple(null, argsToTake); tps = new TemplateParameterSymbol(tpar, tt); // and set the actual template tuple parameter deduction deducedTypeDict[tpar] = tps; } add = true; return(true); }
ISemantic E(PostfixExpression_MethodCall call, bool returnBaseTypeOnly = true) { // Deduce template parameters later on AbstractType[] baseExpression = null; ISymbolValue baseValue = null; TemplateInstanceExpression tix = null; bool isUFCSFunction = false; GetRawCallOverloads(call, out baseExpression, out baseValue, out tix, out isUFCSFunction); var methodOverloads = new List <AbstractType>(); #region Search possible methods, opCalls or delegates that could be called bool requireStaticItems = true; //TODO: What if there's an opCall and a foreign method at the same time? - and then this variable would be bullshit IEnumerable <AbstractType> scanResults = DResolver.StripAliasSymbols(baseExpression); var nextResults = new List <AbstractType>(); while (scanResults != null) { foreach (var b in scanResults) { if (b is MemberSymbol) { var mr = (MemberSymbol)b; if (mr.Definition is DMethod) { methodOverloads.Add(mr); continue; } else if (mr.Definition is DVariable) { // If we've got a variable here, get its base type/value reference if (eval) { var dgVal = ValueProvider[(DVariable)mr.Definition] as DelegateValue; if (dgVal != null) { nextResults.Add(dgVal.Definition); continue; } else { throw new EvaluationException(call, "Variable must be a delegate, not anything else", mr); } } else { var bt = DResolver.StripAliasSymbol(mr.Base ?? TypeDeclarationResolver.ResolveSingle(mr.Definition.Type, ctxt)); // Must be of type delegate if (bt is DelegateType) { //TODO: Ensure that there's no further overload - inform the user elsewise if (returnBaseTypeOnly) { return(bt); } else { return(new MemberSymbol(mr.Definition, bt, mr.DeclarationOrExpressionBase)); } } else { /* * If mr.Node is not a method, so e.g. if it's a variable * pointing to a delegate * * class Foo * { * string opCall() { return "asdf"; } * } * * Foo f=new Foo(); * f(); -- calls opCall, opCall is not static */ nextResults.Add(bt); requireStaticItems = false; } //TODO: Can other types work as function/are callable? } } } else if (b is DelegateType) { var dg = (DelegateType)b; /* * int a = delegate(x) { return x*2; } (12); // a is 24 after execution * auto dg=delegate(x) {return x*3;}; * int b = dg(4); */ if (dg.IsFunctionLiteral) { methodOverloads.Add(dg); } else { // If it's just wanted to pass back the delegate's return type, skip the remaining parts of this method. if (eval) { throw new EvaluationException(call, "TODO", dg); } //TODO //if(returnBaseTypeOnly) //TODO: Check for multiple definitions. Also, make a parameter-argument check to inform the user about wrong arguments. return(dg); } } else if (b is ClassType) { /* * auto a = MyStruct(); -- opCall-Overloads can be used */ var classDef = ((ClassType)b).Definition; if (classDef == null) { continue; } foreach (var i in classDef) { if (i.Name == "opCall" && i is DMethod && (!requireStaticItems || (i as DNode).IsStatic)) { methodOverloads.Add(TypeDeclarationResolver.HandleNodeMatch(i, ctxt, b, call) as MemberSymbol); } } } /* * Every struct can contain a default ctor: * * struct S { int a; bool b; } * * auto s = S(1,true); -- ok * auto s2= new S(2,false); -- error, no constructor found! */ else if (b is StructType && methodOverloads.Count == 0) { //TODO: Deduce parameters return(b); } /* * If the overload is a template, it quite exclusively means that we'll handle a method that is the only * child inside a template + that is named as the template. */ else if (b is TemplateType && ImplicitTemplateProperties.ContainsEquallyNamedChildrenOnly(((TemplateType)b).Definition)) { methodOverloads.Add(b); } } scanResults = nextResults.Count == 0 ? null : nextResults.ToArray(); nextResults.Clear(); } #endregion if (methodOverloads.Count == 0) { return(null); } // Get all arguments' types var callArguments = new List <ISemantic>(); // If it's sure that we got a ufcs call here, add the base expression's type as first argument type if (isUFCSFunction) { callArguments.Add(eval ? (ISemantic)baseValue : ((MemberSymbol)baseExpression[0]).Base); } if (call.Arguments != null) { foreach (var arg in call.Arguments) { callArguments.Add(E(arg)); } } #region Deduce template parameters and filter out unmatching overloads // First add optionally given template params // http://dlang.org/template.html#function-templates var tplParamDeductionArguments = tix == null ? new List <ISemantic>() : TemplateInstanceHandler.PreResolveTemplateArgs(tix, ctxt); // Then add the arguments[' member types] foreach (var arg in callArguments) { if (arg is VariableValue) { tplParamDeductionArguments.Add(ValueProvider[((VariableValue)arg).Variable]); } else if (arg is AbstractType) { tplParamDeductionArguments.Add(DResolver.StripMemberSymbols((AbstractType)arg)); } else { tplParamDeductionArguments.Add(arg); } } var templateParamFilteredOverloads = TemplateInstanceHandler.DeduceParamsAndFilterOverloads( methodOverloads, tplParamDeductionArguments.Count > 0 ? tplParamDeductionArguments.ToArray() : null, true, ctxt); #endregion #region Filter by parameter-argument comparison var argTypeFilteredOverloads = new List <AbstractType>(); if (templateParamFilteredOverloads != null) { foreach (var ov in templateParamFilteredOverloads) { if (ov is MemberSymbol) { var ms = (MemberSymbol)ov; var dm = ms.Definition as DMethod; bool add = false; if (dm != null) { ctxt.CurrentContext.IntroduceTemplateParameterTypes(ms); add = false; if (callArguments.Count == 0 && dm.Parameters.Count == 0) { add = true; } else { for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = TypeDeclarationResolver.ResolveSingle(dm.Parameters[i].Type, ctxt); // TODO: Expression tuples & variable argument lengths if (i >= callArguments.Count || !ResultComparer.IsImplicitlyConvertible(callArguments[i], paramType, ctxt)) { continue; } add = true; } } if (add) { var bt = ms.Base ?? TypeDeclarationResolver.GetMethodReturnType(dm, ctxt); if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { argTypeFilteredOverloads.Add(ms.Base == null ? new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) : ms); } } ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(ms); } } else if (ov is DelegateType) { var dg = (DelegateType)ov; var bt = TypeDeclarationResolver.GetMethodReturnType(dg, ctxt); //TODO: Param-Arg check if (returnBaseTypeOnly) { argTypeFilteredOverloads.Add(bt); } else { argTypeFilteredOverloads.Add(new DelegateType(bt, dg.DeclarationOrExpressionBase as FunctionLiteral, dg.Parameters)); } } } } #endregion if (eval) { // Convert ISemantic[] to ISymbolValue[] var args = new List <ISymbolValue>(callArguments.Count); foreach (var a in callArguments) { args.Add(a as ISymbolValue); } // Execute/Evaluate the variable contents etc. return(TryDoCTFEOrGetValueRefs(argTypeFilteredOverloads.ToArray(), call.PostfixForeExpression, true, args.ToArray())); } else { // Check if one overload remains and return that one. ctxt.CheckForSingleResult(argTypeFilteredOverloads.ToArray(), call); return(argTypeFilteredOverloads != null && argTypeFilteredOverloads.Count != 0 ? argTypeFilteredOverloads[0] : null); } }
/// <summary> /// a + b; a - b; etc. /// </summary> ISemantic E_MathOp(OperatorBasedExpression x, ISemantic lValue = null, ISemantic rValue = null) { if (!eval) { return(lValue ?? E(x.LeftOperand)); } var l = TryGetValue(lValue ?? E(x.LeftOperand)); if (l == null) { /* * In terms of adding opOverloading later on, * lvalue not being a PrimitiveValue shouldn't be a problem anymore - we simply had to * search the type of l for methods called opAdd etc. and call that method via ctfe. * Finally, return the value the opAdd method passed back - and everything is fine. */ /* * Also, pointers should be implemented later on. * http://dlang.org/expression.html#AddExpression */ throw new EvaluationException(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", lValue); } //TODO: Operator overloading // Note: a * b + c is theoretically treated as a * (b + c), but it's needed to evaluate it as (a * b) + c ! if (x is MulExpression || x is PowExpression) { if (x.RightOperand is OperatorBasedExpression && !(x.RightOperand is AssignExpression)) //TODO: This must be true only if it's a math expression, so not an assign expression etc. { var sx = (OperatorBasedExpression)x.RightOperand; // Now multiply/divide/mod expression 'l' with sx.LeftOperand var intermediateResult = HandleSingleMathOp(x, l, E(sx.LeftOperand), mult); // afterwards, evaluate the operation between the result just returned and the sx.RightOperand. return(E(sx, intermediateResult)); } return(HandleSingleMathOp(x, l, rValue ?? E(x.RightOperand), mult)); } var r = TryGetValue(rValue ?? E(x.RightOperand)); if (r == null) { throw new EvaluationException(x, "Right operand must evaluate to a value", lValue); } /* * TODO: Handle invalid values/value ranges. */ if (x is XorExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value ^ (long)b.Value; })); } else if (x is OrExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value | (long)b.Value; })); } else if (x is AndExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); return (long)a.Value & (long)b.Value; })); } else if (x is ShiftExpression) { return(HandleSingleMathOp(x, l, r, (a, b) => { EnsureIntegralType(a); EnsureIntegralType(b); if (b.Value < 0 || b.Value > 31) { throw new EvaluationException(b.BaseExpression, "Shift operand must be between 0 and 31", b); } switch (x.OperatorToken) { case DTokens.ShiftLeft: return (long)a.Value << (int)b.Value; // TODO: Handle the imaginary part case DTokens.ShiftRight: return (long)a.Value >> (int)b.Value; case DTokens.ShiftRightUnsigned: //TODO: Find out where's the difference between >> and >>> return (ulong)a.Value >> (int)(uint)b.Value; } throw new EvaluationException(x, "Invalid token for shift expression", l, r); })); } else if (x is AddExpression) { return(HandleSingleMathOp(x, l, r, (a, b, op) => { switch (op.OperatorToken) { case DTokens.Plus: return new PrimitiveValue(a.BaseTypeToken, a.Value + b.Value, x, a.ImaginaryPart + b.ImaginaryPart); case DTokens.Minus: return new PrimitiveValue(a.BaseTypeToken, a.Value - b.Value, x, a.ImaginaryPart - b.ImaginaryPart); } throw new EvaluationException(x, "Invalid token for add/sub expression", l, r); })); } else if (x is CatExpression) { // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array var av_l = l as ArrayValue; var av_r = r as ArrayValue; if (av_l != null && av_r != null) { // Ensure that both arrays are of the same type if (!ResultComparer.IsEqual(av_l.RepresentedType, av_r.RepresentedType)) { throw new EvaluationException(x, "Both arrays must be of same type", l, r); } // Might be a string if (av_l.IsString && av_r.IsString) { return(new ArrayValue(av_l.RepresentedType as ArrayType, x, av_l.StringValue + av_r.StringValue)); } else { var elements = new ISymbolValue[av_l.Elements.Length + av_r.Elements.Length]; Array.Copy(av_l.Elements, 0, elements, 0, av_l.Elements.Length); Array.Copy(av_r.Elements, 0, elements, av_l.Elements.Length, av_r.Elements.Length); return(new ArrayValue(av_l.RepresentedType as ArrayType, elements)); } } ArrayType at = null; // Append the right value to the array if (av_l != null && (at = av_l.RepresentedType as ArrayType) != null && ResultComparer.IsImplicitlyConvertible(r.RepresentedType, at.ValueType, ctxt)) { var elements = new ISymbolValue[av_l.Elements.Length + 1]; Array.Copy(av_l.Elements, elements, av_l.Elements.Length); elements[elements.Length - 1] = r; return(new ArrayValue(at, elements)); } // Put the left value into the first position else if (av_r != null && (at = av_r.RepresentedType as ArrayType) != null && ResultComparer.IsImplicitlyConvertible(l.RepresentedType, at.ValueType, ctxt)) { var elements = new ISymbolValue[1 + av_r.Elements.Length]; elements[0] = l; Array.Copy(av_r.Elements, 0, elements, 1, av_r.Elements.Length); return(new ArrayValue(at, elements)); } throw new EvaluationException(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", l, r); } throw new WrongEvaluationArgException(); }
ISymbolValue EvalConcatenation(CatExpression x, ISymbolValue lValue) { // In the (not unusual) case that more than 2 arrays/strings shall be concat'ed - process them more efficiently var catQueue = new Queue <ISymbolValue>(); var catEx = (x as CatExpression); catQueue.Enqueue(lValue); catEx = catEx.RightOperand as CatExpression; ISymbolValue r; while (catEx != null) { r = TryGetValue(E(catEx.LeftOperand)); if (r == null) { EvalError(catEx.LeftOperand, "Couldn't be evaluated."); return(null); } catQueue.Enqueue(r); if (catEx.RightOperand is CatExpression) { catEx = catEx.RightOperand as CatExpression; } else { break; } } r = TryGetValue(E((catEx ?? x).RightOperand)); if (r == null) { EvalError(catEx.LeftOperand, "Couldn't be evaluated."); return(null); } catQueue.Enqueue(r); // Notable: If one element is of the value type of the array, the element is added (either at the front or at the back) to the array // myString ~ 'a' will append an 'a' to the string // 'a' ~ myString inserts 'a' at index 0 // Determine whether we have to build up a string OR a normal list of atomic elements bool isString = true; ArrayType lastArrayType = null; foreach (var e in catQueue) { if (e is AssociativeArrayValue) { EvalError(x, "Can't concatenate associative arrays", e); return(null); } else if (e is ArrayValue) { if (lastArrayType != null && !ResultComparer.IsEqual(lastArrayType, e.RepresentedType)) { EvalError(x, "Both arrays must be of same type", new[] { lastArrayType, e.RepresentedType }); return(null); } lastArrayType = e.RepresentedType as ArrayType; if ((e as ArrayValue).IsString) { continue; } } else if (e is PrimitiveValue) { var btt = (e as PrimitiveValue).BaseTypeToken; if (btt == DTokens.Char || btt == DTokens.Dchar || btt == DTokens.Wchar) { continue; } } isString = false; } if (lastArrayType == null) { EvalError(x, "At least one operand must be an (non-associative) array. If so, the other operand must be of the array's element type.", catQueue.ToArray()); return(null); } if (isString) { var sb = new StringBuilder(); while (catQueue.Count != 0) { var e = catQueue.Dequeue(); if (e is ArrayValue) { sb.Append((e as ArrayValue).StringValue); } else if (e is PrimitiveValue) { sb.Append((char)((e as PrimitiveValue).Value)); } } return(new ArrayValue(GetStringType(LiteralSubformat.Utf8), sb.ToString())); } var elements = new List <ISymbolValue>(); while (catQueue.Count != 0) { var e = catQueue.Dequeue(); var av = e as ArrayValue; if (av != null) { if (av.IsString) { elements.Add(av); } else if (av.Elements != null) { elements.AddRange(av.Elements); } continue; } if (!ResultComparer.IsImplicitlyConvertible(e.RepresentedType, lastArrayType.ValueType, ctxt)) { EvalError(x, "Element with type " + e.RepresentedType.ToCode() + " doesn't fit into array with type " + lastArrayType.ToCode(), catQueue.ToArray()); return(null); } elements.Add(e); } return(new ArrayValue(lastArrayType, elements.ToArray())); }
public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol) { DSymbol ds = null; mightBeLegalUnresolvableSymbol = false; if (string.IsNullOrWhiteSpace(symName)) { return(null); } // Try to handle a probably mangled string or C function. if (symName.StartsWith("_")) { try{ ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol; }catch {} } // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[]) if (ds == null && Lexer.IsIdentifierPart((int)symName[0])) { mightBeLegalUnresolvableSymbol = true; ITypeDeclaration q; var method = DParser.ParseMethodDeclarationHeader(symName, out q); q = Demangler.RemoveNestedTemplateRefsFromQualifier(q); method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type); var methodType = TypeDeclarationResolver.GetMethodReturnType(method, ctxt); var methodParameters = new List <AbstractType>(); if (method.Parameters != null && method.Parameters.Count != 0) { foreach (var parm in method.Parameters) { methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt)); } } ctxt.ContextIndependentOptions |= ResolutionOptions.IgnoreAllProtectionAttributes; var overloads = TypeDeclarationResolver.Resolve(q, ctxt); if (overloads == null || overloads.Length == 0) { return(null); } else if (overloads.Length == 1) { ds = overloads[0] as DSymbol; } else { foreach (var o in overloads) { ds = o as DSymbol; if (ds == null || !(ds.Definition is DMethod)) { continue; } var dm = ds.Definition as DMethod; // Compare return types if (dm.Type != null) { if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base)) { continue; } } else if (dm.Type == null && methodType != null) { return(null); } // Compare parameters if (methodParameters.Count != dm.Parameters.Count) { continue; } for (int i = 0; i < methodParameters.Count; i++) { if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt))) { continue; } } } } } if (ds != null) { return(ds.Definition); } return(null); }
public static DNode ExamTraceSymbol(string symName, ResolutionContext ctxt, out bool mightBeLegalUnresolvableSymbol) { DSymbol ds = null; mightBeLegalUnresolvableSymbol = false; if (string.IsNullOrWhiteSpace(symName)) { return(null); } // Try to handle a probably mangled string or C function. if (symName.StartsWith("_")) { try{ ds = Demangler.DemangleAndResolve(symName, ctxt) as DSymbol; }catch {} } // Stuff like void std.stdio.File.LockingTextWriter.put!(immutable(char)[]).put(immutable(char)[]) if (ds == null && Lexer.IsIdentifierPart((int)symName[0])) { mightBeLegalUnresolvableSymbol = true; ITypeDeclaration q; var method = DParser.ParseMethodDeclarationHeader(symName, out q); q = Demangler.RemoveNestedTemplateRefsFromQualifier(q); AbstractType[] overloads = null; D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { try { overloads = AmbiguousType.TryDissolve(LooseResolution.LookupIdRawly(ctxt.ParseCache, q, ctxt.ScopedBlock.NodeRoot as DModule)).ToArray(); } catch (Exception ex) { MonoDevelop.Core.LoggingService.LogWarning("Error during trace.log symbol resolution of " + q.ToString(), ex); } }); if (overloads == null || overloads.Length == 0) { return(null); } else if (overloads.Length == 1) { ds = overloads[0] as DSymbol; } else { method.Type = Demangler.RemoveNestedTemplateRefsFromQualifier(method.Type); var methodType = TypeDeclarationResolver.GetMethodReturnType(method, ctxt); var methodParameters = new List <AbstractType>(); D_Parser.Completion.CodeCompletion.DoTimeoutableCompletionTask(null, ctxt, () => { if (method.Parameters != null && method.Parameters.Count != 0) { foreach (var parm in method.Parameters) { methodParameters.Add(TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(parm.Type), ctxt)); } } }); foreach (var o in overloads) { ds = o as DSymbol; if (ds == null || !(ds.Definition is DMethod)) { continue; } var dm = ds.Definition as DMethod; // Compare return types if (dm.Type != null) { if (methodType == null || ds.Base == null || !ResultComparer.IsEqual(methodType, ds.Base)) { continue; } } else if (dm.Type == null && methodType != null) { return(null); } // Compare parameters if (methodParameters.Count != dm.Parameters.Count) { continue; } for (int i = 0; i < methodParameters.Count; i++) { if (!ResultComparer.IsImplicitlyConvertible(methodParameters[i], TypeDeclarationResolver.ResolveSingle(Demangler.RemoveNestedTemplateRefsFromQualifier(dm.Parameters[i].Type), ctxt))) { continue; } } } } } return(ds != null ? ds.Definition : null); }