public bool IsMatching(StaticIfCondition sc, ResolutionContext ctxt) { if (conditionsBeingChecked.Contains(sc) || ctxt == null) { return(false); } conditionsBeingChecked.Add(sc); ISymbolValue v = null; /*if (System.Threading.Interlocked.Increment(ref stk) > 5) * { * }*/ try { v = Evaluation.EvaluateValue(sc.Expression, ctxt); if (v is VariableValue) { v = Evaluation.EvaluateValue(((VariableValue)v).Variable.Initializer, ctxt); } } finally { conditionsBeingChecked.Remove(sc); } //System.Threading.Interlocked.Decrement(ref stk); return(!Evaluation.IsFalseZeroOrNull(v)); //TODO: Just because the expression evaluation isn't working properly currently, let it return true to have it e.g. in the completion list }
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)) throw new EvaluationException(BaseExpression, value.ToCode() + " must be implicitly convertible to the array's value type!", value); // 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 throw new EvaluationException(BaseExpression, "Type of accessed item must be an array", oldV); }
public TemplateParameterSymbol(TemplateParameter tpn, ISemantic typeOrValue, ISyntaxRegion paramIdentifier = null) : base(tpn != null ? tpn.Representation : null, AbstractType.Get(typeOrValue), paramIdentifier) { IsKnowinglyUndetermined = TemplateInstanceHandler.IsNonFinalArgument(typeOrValue); this.Parameter = tpn; this.ParameterValue = typeOrValue as ISymbolValue; }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { if (vp != null && vp.ev != null) { vp.ev.EvalError(null, "Cannot assign a value to a static property.", new[] { this, value }); } //TODO: What about array.length? }
/// <summary> /// Removes all variable references by resolving them via the given value provider. /// Useful when only the value is of interest, not its container or other things. /// </summary> public static ISymbolValue GetVariableContents(ISymbolValue v, AbstractSymbolValueProvider vp) { while (v is VariableValue) { v = vp[(v as VariableValue).Variable]; } return(v); }
public TemplateParameterSymbol(ITemplateParameter tp, ISemantic representedTypeOrValue, ISyntaxRegion originalParameterIdentifier = null, DNode parentNode = null) : base(new TemplateParameterNode(tp) { Parent = parentNode }, AbstractType.Get(representedTypeOrValue), originalParameterIdentifier ?? tp) { this.Parameter = tp; this.ParameterValue = representedTypeOrValue as ISymbolValue; }
public static bool IsEqual(ISymbolValue l, ISymbolValue r) { // If they are integral values or pointers, equality is defined as the bit pattern of the type matches exactly if (l is PrimitiveValue && r is PrimitiveValue) { var pv_l = (PrimitiveValue)l; var pv_r = (PrimitiveValue)r; return pv_l.Value == pv_r.Value && pv_l.ImaginaryPart == pv_r.ImaginaryPart; } else if(l is AssociativeArrayValue && r is AssociativeArrayValue) { var aa_l = l as AssociativeArrayValue; var aa_r = r as AssociativeArrayValue; if(aa_l.Elements == null || aa_l.Elements.Count == 0) return aa_r.Elements == null || aa_r.Elements.Count == 0; else if(aa_r.Elements != null && aa_r.Elements.Count == aa_l.Elements.Count) { //TODO: Check if each key of aa_l can be found somewhere in aa_r. //TODO: If respective keys are equal, check if values are equal return true; } } else if(l is ArrayValue && r is ArrayValue) { var av_l = l as ArrayValue; var av_r = r as ArrayValue; if(av_l.IsString == av_r.IsString) { if(av_l.IsString) return av_l.StringValue == av_r.StringValue; else { if(av_l.Elements == null || av_l.Elements.Length == 0) return av_r.Elements == null || av_r.Elements.Length == 0; else if(av_r.Elements != null && av_r.Elements.Length == av_l.Elements.Length) { for(int i = av_l.Elements.Length-1; i != -1; i--) { if(!IsEqual(av_l.Elements[i], av_r.Elements[i])) return false; } return true; } } } } return false; }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { var oldV = vp[Variable]; if (oldV is AssociativeArrayValue) { if (Key != null) { var aa = (AssociativeArrayValue)oldV; int itemToReplace = -1; for (int i = 0; i < aa.Elements.Count; i++) { if (SymbolValueComparer.IsEqual(aa.Elements[i].Key, Key)) { itemToReplace = i; break; } } // If we haven't found a matching key, add it to the array var newElements = new KeyValuePair <ISymbolValue, ISymbolValue> [aa.Elements.Count + (itemToReplace == -1 ? 1: 0)]; aa.Elements.CopyTo(newElements, 0); if (itemToReplace != -1) { newElements[itemToReplace] = new KeyValuePair <ISymbolValue, ISymbolValue>(newElements[itemToReplace].Key, value); } else { newElements[newElements.Length - 1] = new KeyValuePair <ISymbolValue, ISymbolValue>(Key, value); } // Finally, make a new associative array containing the new elements vp[Variable] = new AssociativeArrayValue(aa.RepresentedType as AssocArrayType, newElements); } else { if (vp.ev != null) { vp.ev.EvalError(null, "Key expression must not be null", Key); } } } else { if (vp.ev != null) { vp.ev.EvalError(null, "Type of accessed item must be an associative array", oldV); } } }
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); } } }
public ISymbolValue Visit(AssignExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); //TODO this.rValue = null; return(null); }
public ISymbolValue Visit(EqualExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); var rValue = this.rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null); this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); var r = TryGetValue(rValue); var isEq = SymbolValueComparer.IsEqual(l, r); return(new PrimitiveValue(x.OperatorToken == DTokens.Equal ? isEq : !isEq, x)); }
public void Add (IExpression x, ISymbolValue v, params ISymbolValue[] argumentValues) { if (x == null || v == null) return; var hashVis = D_Parser.Dom.Visitors.AstElementHashingVisitor.Instance; long hash = 0; foreach (var arg in argumentValues) unchecked { hash += arg.Accept (hashVis); } cache.Add (v, x, hash); }
public static bool IsFalseZeroOrNull(ISymbolValue v) { var pv = v as PrimitiveValue; if (pv != null) { try { return(pv.Value == 0m); } catch { } } else { return(v is NullValue); } return(v != null); }
ObjectValue CreateObjectValue(ISymbolValue v, IExpression originalExpression, ObjectPath pathOpt, EvaluationOptions evalOptions, IDBacktraceSymbol symbolOpt = null) { if (v != null) { try { return(v.Accept(new ObjectValueSynthVisitor(this) { evalOptions = evalOptions, OriginalExpression = originalExpression, Path = pathOpt })); } catch (NotImplementedException) { } } if (symbolOpt != null) { return(ObjectValue.CreatePrimitive(this, pathOpt, symbolOpt.TypeName, new Mono.Debugging.Backend.EvaluationResult(symbolOpt.Value), ObjectValueFlags.Variable)); } return(ObjectValue.CreateError(this, pathOpt, "", "Couldn't evaluate expression " + (originalExpression != null ? originalExpression.ToString() : ""), ObjectValueFlags.Error)); }
// Define a symbols value public void Define(string symbol, ISymbolValue value, bool canReplace = false) { if (!canReplace) { // Check not already defined in an outer scope var outerScope = ContainingScope; if (outerScope != null && outerScope.IsSymbolDefined(symbol)) { throw new InvalidOperationException(string.Format("The symbol '{0}' is already defined in an outer scope", symbol)); } // Check if already defined ISymbolValue existing; if (_symbols.TryGetValue(symbol, out existing)) { throw new InvalidOperationException(string.Format("Duplicate symbol: '{0}'", symbol)); } } // Store it _symbols[symbol] = value; _weakMatchTable = null; }
/// <summary> /// /// </summary> /// <param name="dm"></param> /// <param name="args"></param> /// <param name="baseValueProvider">Required for evaluating missing default parameters.</param> public static bool AssignCallArgumentsToIC(DMethod dm, ISymbolValue[] args, AbstractSymbolValueProvider baseValueProvider, out Dictionary<DVariable,ISymbolValue> targetArgs) { targetArgs = new Dictionary<DVariable, ISymbolValue>(); var argsRemaining = args != null ? args.Length : 0; int argu = 0; for (int para = 0; para < dm.Parameters.Count; para++) { var par = dm.Parameters[para] as DVariable; if (par.Type is VarArgDecl && argsRemaining > 0) { var va_args = new ISemantic[argsRemaining]; args.CopyTo(va_args, argu); argsRemaining=0; //TODO: Assign a value tuple to par if (++para < dm.Parameters.Count) return false; } if (argsRemaining > 0) { targetArgs[par] = args[argu++]; argsRemaining--; } else if (par.Initializer != null) { targetArgs[par] = Evaluation.EvaluateValue(par.Initializer, baseValueProvider); } else return false; } return argsRemaining == 0; }
public AssocArrayPointer(MemberSymbol assocArrayVariable, ISymbolValue accessedItemKey) : base(assocArrayVariable) { Key = accessedItemKey; }
bool HandleDecl(TemplateTypeParameter parameterRef, ArrayDecl arrayDeclToCheckAgainst, AssocArrayType argumentArrayType) { if (argumentArrayType == null) { return(false); } // Handle key type var at = argumentArrayType as ArrayType; if ((arrayDeclToCheckAgainst.ClampsEmpty == (at == null)) && (at == null || !at.IsStaticArray || arrayDeclToCheckAgainst.KeyExpression == null)) { return(false); } bool result; if (arrayDeclToCheckAgainst.KeyExpression != null) { // Remove all surrounding parentheses from the expression var x_param = arrayDeclToCheckAgainst.KeyExpression; while (x_param is SurroundingParenthesesExpression) { x_param = ((SurroundingParenthesesExpression)x_param).Expression; } var ad_Argument = argumentArrayType.DeclarationOrExpressionBase as ArrayDecl; /* * This might be critical: * the [n] part in class myClass(T:char[n], int n) {} * will be seen as an identifier expression, not as an identifier declaration. * So in the case the parameter expression is an identifier, * test if it's part of the parameter list */ var id = x_param as IdentifierExpression; if (id != null && id.IsIdentifier && Contains(id.ValueStringHash)) { // If an expression (the usual case) has been passed as argument, evaluate its value, otherwise is its type already resolved. ISemantic finalArg = null; if (ad_Argument != null && ad_Argument.KeyExpression != null) { ISymbolValue val = null; int len = -1; finalArg = TypeDeclarationResolver.ResolveKey(ad_Argument, out len, out val, ctxt); if (val != null) { finalArg = val; } } else { finalArg = argumentArrayType.KeyType; } //TODO: Do a type convertability check between the param type and the given argument's type. // The affected parameter must also be a value parameter then, if an expression was given. // and handle it as if it was an identifier declaration.. result = Set(parameterRef, finalArg, id.ValueStringHash); } else if (ad_Argument != null && ad_Argument.KeyExpression != null) { // Just test for equality of the argument and parameter expression, e.g. if both param and arg are 123, the result will be true. result = SymbolValueComparer.IsEqual(arrayDeclToCheckAgainst.KeyExpression, ad_Argument.KeyExpression, new StandardValueProvider(ctxt)); } else { result = false; } if (!result) { return(false); } } else if (arrayDeclToCheckAgainst.KeyType != null) { // If the array we're passing to the decl check that is static (i.e. has a constant number as key 'type'), // pass that number instead of type 'int' to the check. if (argumentArrayType != null && at != null && at.IsStaticArray) { result = HandleDecl(parameterRef, arrayDeclToCheckAgainst.KeyType, new PrimitiveValue(D_Parser.Parser.DTokens.Int, (decimal)at.FixedLength, null)); } else { result = HandleDecl(parameterRef, arrayDeclToCheckAgainst.KeyType, argumentArrayType.KeyType); } if (!result) { return(false); } } // Handle inner type return(HandleDecl(parameterRef, arrayDeclToCheckAgainst.InnerDeclaration, argumentArrayType.Base)); }
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(catEx.LeftOperand != null ? catEx.LeftOperand.Accept(this) : null); if(r == null || r is NullValue) { EvalError(catEx.LeftOperand, "Couldn't be evaluated."); return null; } catQueue.Enqueue(r); if(catEx.RightOperand is CatExpression) catEx = catEx.RightOperand as CatExpression; else break; } var rightOp = (catEx ?? x).RightOperand; r = TryGetValue(rightOp != null ? rightOp.Accept(this) : null); if(r == null) { EvalError((catEx ?? x).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 != null ? 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()); }
protected override Tuple <CodeLocation, CodeLocation, string> Process( EditorData editorData, bool evaluateUnderneathExpression) { // codeOffset+1 because otherwise it does not work on the first character editorData.CaretOffset++; var sr = DResolver.GetScopedCodeObject(editorData); if (sr == null) { return(Tuple.Create(CodeLocation.Empty, CodeLocation.Empty, String.Empty)); } var types = LooseResolution.ResolveTypeLoosely(editorData, sr, out _, true); if (editorData.CancelToken.IsCancellationRequested) { return(Tuple.Create(CodeLocation.Empty, CodeLocation.Empty, String.Empty)); } if (types == null) { return(Tuple.Create(sr.Location, sr.EndLocation, String.Empty)); } var tipText = new StringBuilder(); DNode dn = null; foreach (var t in AmbiguousType.TryDissolve(types)) { var dt = t; if (dt is AliasedType at) { // jump to original definition if it is not renamed or the caret is on the import var isRenamed = (at.Definition as ImportSymbolAlias)?.ImportBinding?.Alias != null; if (!isRenamed || at.Definition.Location == sr.Location) { dt = at.Base; } } tipText.Append(NodeToolTipContentGen.Instance.GenTooltipSignature(dt)); if (dt is DSymbol symbol) { dn = symbol.Definition; } tipText.Append("\a"); } while (tipText.Length > 0 && tipText[tipText.Length - 1] == '\a') { tipText.Length--; } if (evaluateUnderneathExpression) { var ctxt = editorData.GetLooseResolutionContext(LooseResolution.NodeResolutionAttempt.Normal); ctxt.Push(editorData); try { ISymbolValue v = null; if (dn is DVariable var && var.Initializer != null && var.IsConst) { v = Evaluation.EvaluateValue(var.Initializer, ctxt); } if (v == null && sr is IExpression expression) { v = Evaluation.EvaluateValue(expression, ctxt); } if (v != null && !(v is ErrorValue)) { var valueStr = " = " + v; if (tipText.Length > valueStr.Length && tipText.ToString(tipText.Length - valueStr.Length, valueStr.Length) != valueStr) { tipText.Append(valueStr); } } } catch (Exception e) { tipText.Append("\aException during evaluation = ").Append(e.Message); } ctxt.Pop(); } if (dn != null) { VDServerCompletionDataGenerator.GenerateNodeTooltipBody(dn, tipText); } while (tipText.Length > 0 && tipText[tipText.Length - 1] == '\a') { tipText.Length--; } return(Tuple.Create(sr.Location, sr.EndLocation, tipText.ToString())); }
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; } }
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; } }
ISemantic E(PostfixExpression_Slice x, ISemantic foreExpression) { if (!eval) return foreExpression; // Still of the array's type. if (!(foreExpression is ArrayValue)){ EvalError(x.PostfixForeExpression, "Must be an array"); return null; } var ar = (ArrayValue)foreExpression; var sl = (PostfixExpression_Slice)x; // If the [ ] form is used, the slice is of the entire array. if (sl.FromExpression == null && sl.ToExpression == null) return foreExpression; // Make $ operand available var arrLen_Backup = ValueProvider.CurrentArrayLength; ValueProvider.CurrentArrayLength = ar.Elements.Length; var bound_lower = E(sl.FromExpression) as PrimitiveValue; var bound_upper = E(sl.ToExpression) as PrimitiveValue; ValueProvider.CurrentArrayLength = arrLen_Backup; if (bound_lower == null || bound_upper == null){ EvalError(bound_lower == null ? sl.FromExpression : sl.ToExpression, "Must be of an integral type"); return null; } int lower = -1, upper = -1; try { lower = Convert.ToInt32(bound_lower.Value); upper = Convert.ToInt32(bound_upper.Value); } catch { EvalError(lower != -1 ? sl.FromExpression : sl.ToExpression, "Boundary expression must base an integral type"); return null; } if (lower < 0){ EvalError(sl.FromExpression, "Lower boundary must be greater than 0");return null;} if (lower >= ar.Elements.Length){ EvalError(sl.FromExpression, "Lower boundary must be smaller than " + ar.Elements.Length);return null;} if (upper < lower){ EvalError(sl.ToExpression, "Upper boundary must be greater than " + lower);return null;} if (upper >= ar.Elements.Length){ EvalError(sl.ToExpression, "Upper boundary must be smaller than " + ar.Elements.Length);return null;} var rawArraySlice = new ISymbolValue[upper - lower]; int j = 0; for (int i = lower; i < upper; i++) rawArraySlice[j++] = ar.Elements[i]; return new ArrayValue(ar.RepresentedType as ArrayType, rawArraySlice); }
public AssocArrayPointer(DVariable accessedArray, AssocArrayType arrayType, ISymbolValue accessedItemKey, IExpression baseExpression) : base(accessedArray, arrayType, baseExpression) { Key = accessedItemKey; }
public static ISymbolValue Execute(DMethod method, ISymbolValue[] arguments, AbstractSymbolValueProvider vp) { throw new NotImplementedException("CTFE is not implemented yet."); }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { throw new EvaluationException(BaseExpression, "Cannot assign a value to a static property.", value); //TODO: What about array.length? }
public static AbstractType ResolveKey(ArrayDecl ad, out int fixedArrayLength, out ISymbolValue keyVal, ResolutionContext ctxt) { keyVal = null; fixedArrayLength = -1; AbstractType keyType = null; if (ad.KeyExpression != null) { //TODO: Template instance expressions? var id_x = ad.KeyExpression as IdentifierExpression; if (id_x != null && id_x.IsIdentifier) { var id = new IdentifierDeclaration((string)id_x.Value) { Location = id_x.Location, EndLocation = id_x.EndLocation }; keyType = TypeDeclarationResolver.ResolveSingle(id, ctxt); if (keyType != null) { var tt = DResolver.StripAliasSymbol(keyType) as MemberSymbol; if (tt == null || !(tt.Definition is DVariable) || ((DVariable)tt.Definition).Initializer == null) return keyType; } } try { keyVal = Evaluation.EvaluateValue(ad.KeyExpression, ctxt); if (keyVal != null) { // Take the value's type as array key type keyType = keyVal.RepresentedType; // It should be mostly a number only that points out how large the final array should be var pv = Evaluation.GetVariableContents(keyVal, new StandardValueProvider(ctxt)) as PrimitiveValue; if (pv != null) { fixedArrayLength = System.Convert.ToInt32(pv.Value); if (fixedArrayLength < 0) ctxt.LogError(ad, "Invalid array size: Length value must be greater than 0"); } //TODO Is there any other type of value allowed? } } catch { } } else { var t = Resolve(ad.KeyType, ctxt); ctxt.CheckForSingleResult(t, ad.KeyType); if (t != null && t.Length != 0) return t[0]; } return keyType; }
/// <summary> /// a + b; a - b; etc. /// </summary> ISymbolValue E_MathOp(OperatorBasedExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); var rValue = this.rValue; this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); 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 */ EvalError(x, "Left value must evaluate to a constant scalar value. Operator overloads aren't supported yet", new[]{lValue}); return null; } //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) { try{ 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 try{ this.lValue = HandleSingleMathOp(x, l, sx.LeftOperand != null ? sx.LeftOperand.Accept(this) : null, mult); // afterwards, evaluate the operation between the result just returned and the sx.RightOperand. return sx.Accept(this); }catch(DivideByZeroException) { EvalError(sx, "Divide by 0"); return null; } } return HandleSingleMathOp(x, l, TryGetValue(rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null)), mult); }catch(DivideByZeroException) { EvalError(x, "Divide by 0"); return null; } } else if (x is CatExpression) { return EvalConcatenation(x as CatExpression, l); } var r = TryGetValue(rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null)); if(r == null){ EvalError(x, "Right operand must evaluate to a value", new[]{rValue}); return null; } /* * TODO: Handle invalid values/value ranges. */ if (x is XorExpression) { return HandleSingleMathOp(x, l,r, (a,b)=>{ if(EnsureIntegralType(x.LeftOperand,a) && EnsureIntegralType(x.RightOperand,b)) return (long)a.Value ^ (long)b.Value; return 0L; }); } else if (x is OrExpression) { return HandleSingleMathOp(x, l, r, (a, b) => { if(EnsureIntegralType(x.LeftOperand,a) && EnsureIntegralType(x.RightOperand,b)) return (long)a.Value | (long)b.Value; return 0L; }); } else if (x is AndExpression) { return HandleSingleMathOp(x, l, r, (a, b) => { if(EnsureIntegralType(x.LeftOperand,a) && EnsureIntegralType(x.RightOperand,b)) return (long)a.Value & (long)b.Value; return 0L; }); } else if (x is ShiftExpression) return HandleSingleMathOp(x, l, r, (a, b) => { if(!EnsureIntegralType(x.LeftOperand, a) || !EnsureIntegralType(x.RightOperand, b)) return 0L; if (b.Value < 0 || b.Value > 31){ EvalError(x, "Shift operand must be between 0 and 31", new[]{b}); return 0m; } 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; } EvalError(x, "Invalid token for shift expression", new[]{l,r}); return 0m; }); 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); } EvalError(x, "Invalid token for add/sub expression", new[]{l,r}); return null; }); throw new WrongEvaluationArgException(); }
ISymbolValue E_BoolOp(OperatorBasedExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); var rValue = this.rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null); this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); var r = TryGetValue(rValue); if (x is OrOrExpression) { // The OrOrExpression evaluates its left operand. // If the left operand, converted to type bool, evaluates to true, // then the right operand is not evaluated. If the result type of the OrOrExpression // is bool then the result of the expression is true. // If the left operand is false, then the right operand is evaluated. // If the result type of the OrOrExpression is bool then the result // of the expression is the right operand converted to type bool. return new PrimitiveValue(!(IsFalseZeroOrNull(l) && IsFalseZeroOrNull(r)), x); } else if (x is AndAndExpression) return new PrimitiveValue(!IsFalseZeroOrNull(l) && !IsFalseZeroOrNull(r), x); else if (x is IdentityExpression) { // http://dlang.org/expression.html#IdentityExpression } else if (x is RelExpression) { return HandleSingleMathOp(x, l, r, (a,b, op) => { // Unordered-ness is when at least one operator is Not any Number (NaN) bool unordered = a.IsNaN || b.IsNaN; bool relationIsTrue=false; bool cmpIm = a.ImaginaryPart != 0 || b.ImaginaryPart != 0; switch(x.OperatorToken) { case DTokens.GreaterThan: // greater, > relationIsTrue = a.Value > b.Value && (!cmpIm || a.ImaginaryPart > b.ImaginaryPart); break; case DTokens.GreaterEqual: // greater or equal, >= relationIsTrue = a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart; break; case DTokens.LessThan: // less, < relationIsTrue = a.Value < b.Value && (!cmpIm || a.ImaginaryPart < b.ImaginaryPart); break; case DTokens.LessEqual: // less or equal, <= relationIsTrue = a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart; break; case DTokens.Unordered: // unordered, !<>= relationIsTrue = unordered; break; case DTokens.LessOrGreater: // less or greater, <> relationIsTrue = (a.Value < b.Value || a.Value > b.Value) && (!cmpIm || (a.ImaginaryPart < b.ImaginaryPart || a.ImaginaryPart > b.ImaginaryPart)); break; case DTokens.LessEqualOrGreater: // less, equal, or greater, <>= relationIsTrue = (a.Value < b.Value || a.Value >= b.Value) && (!cmpIm || (a.ImaginaryPart < b.ImaginaryPart || a.ImaginaryPart >= b.ImaginaryPart)); break; case DTokens.UnorderedOrGreater: // unordered or greater, !<= relationIsTrue = unordered || (a.Value > b.Value && (!cmpIm || a.ImaginaryPart > b.ImaginaryPart)); break; case DTokens.UnorderedGreaterOrEqual: // unordered, greater, or equal, !< relationIsTrue = unordered || (a.Value >= b.Value && a.ImaginaryPart >= b.ImaginaryPart); break; case DTokens.UnorderedOrLess: // unordered or less, !>= relationIsTrue = unordered || (a.Value < b.Value && (!cmpIm || a.ImaginaryPart < b.ImaginaryPart)); break; case DTokens.UnorderedLessOrEqual: // unordered, less, or equal, !> relationIsTrue = unordered || (a.Value <= b.Value && a.ImaginaryPart <= b.ImaginaryPart); break; case DTokens.UnorderedOrEqual: // unordered or equal, !<> relationIsTrue = unordered || (a.Value == b.Value && a.ImaginaryPart == b.ImaginaryPart); break; } return new PrimitiveValue(relationIsTrue, op); }, false); } EvalError(x, "Wrong expression"); return 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; } }
static void HandleDMethodOverload(ResolutionContext ctxt, bool eval, ISymbolValue baseValue, List <ISemantic> callArguments, bool returnBaseTypeOnly, List <AbstractType> argTypeFilteredOverloads, ref bool hasHandledUfcsResultBefore, MemberSymbol ms, ref AbstractType untemplatedMethod) { var dm = ms.Definition as DMethod; if (dm == null) { return; } ISemantic firstUfcsArg; bool isUfcs = UFCSResolver.IsUfcsResult(ms, out firstUfcsArg); // In the case of an ufcs, insert the first argument into the CallArguments list if (isUfcs && !hasHandledUfcsResultBefore) { callArguments.Insert(0, eval ? baseValue as ISemantic : firstUfcsArg); hasHandledUfcsResultBefore = true; } else if (!isUfcs && hasHandledUfcsResultBefore) // In the rare case of having a ufcs result occuring _after_ a normal member result, remove the initial arg again { callArguments.RemoveAt(0); hasHandledUfcsResultBefore = false; } if (dm.Parameters.Count == 0 && callArguments.Count > 0) { return; } var deducedTypeDict = new DeducedTypeDictionary(ms); var templateParamDeduction = new TemplateParameterDeduction(deducedTypeDict, ctxt); var back = ctxt.ScopedBlock; using (ctxt.Push(ms)) { if (ctxt.ScopedBlock != back) { ctxt.CurrentContext.DeducedTemplateParameters = deducedTypeDict; } bool add = true; int currentArg = 0; if (dm.Parameters.Count > 0 || callArguments.Count > 0) { bool hadDTuples = false; for (int i = 0; i < dm.Parameters.Count; i++) { var paramType = dm.Parameters[i].Type; // Handle the usage of tuples: Tuples may only be used as as-is, so not as an array, pointer or in a modified way.. if (paramType is IdentifierDeclaration && (hadDTuples |= TryHandleMethodArgumentTuple(ctxt, ref add, callArguments, dm, deducedTypeDict, i, ref currentArg))) { continue; } else if (currentArg < callArguments.Count) { if (!(add = templateParamDeduction.HandleDecl(null, paramType, callArguments[currentArg++]))) { break; } } else { // If there are more parameters than arguments given, check if the param has default values add = !(dm.Parameters[i] is DVariable) || (dm.Parameters[i] as DVariable).Initializer != null; // Assume that all further method parameters do have default values - and don't check further parameters break; } } // Too few args if (!hadDTuples && currentArg < callArguments.Count) { add = false; } } if (!add) { return; } // If type params were unassigned, try to take the defaults if (dm.TemplateParameters != null) { foreach (var tpar in dm.TemplateParameters) { if (deducedTypeDict[tpar] == null && !templateParamDeduction.Handle(tpar, null)) { return; } } } if (deducedTypeDict.AllParamatersSatisfied) { ms.DeducedTypes = deducedTypeDict.ToReadonly(); var bt = TypeDeclarationResolver.GetMethodReturnType(dm, ctxt) ?? ms.Base; if (eval || !returnBaseTypeOnly) { bt = new MemberSymbol(dm, bt, ms.DeclarationOrExpressionBase, ms.DeducedTypes) { Tag = ms.Tag } } ; if (dm.TemplateParameters == null || dm.TemplateParameters.Length == 0) { untemplatedMethod = bt; //ISSUE: Have another state that indicates an ambiguous non-templated method matching. } argTypeFilteredOverloads.Add(bt); } } }
public static ISymbolValue Execute(MemberSymbol method, ISymbolValue[] arguments, AbstractSymbolValueProvider vp) { return new ErrorValue(new EvaluationException("CTFE is not implemented yet.")); }
/// <summary> /// Evaluates the identifier/template instance as usual. /// If the id points to a variable, the initializer/dynamic value will be evaluated using its initializer. /// /// If ImplicitlyExecute is false but value evaluation is switched on, an InternalOverloadValue-object will be returned /// that keeps all overloads passed via 'overloads' /// </summary> ISemantic TryDoCTFEOrGetValueRefs(AbstractType[] overloads, IExpression idOrTemplateInstance, bool ImplicitlyExecute = true, ISymbolValue[] executionArguments=null) { if (overloads == null || overloads.Length == 0){ EvalError(idOrTemplateInstance, "No symbols found"); return null; } var r = overloads[0]; const string ambigousExprMsg = "Ambiguous expression"; if(r is TemplateParameterSymbol) { var tps = (TemplateParameterSymbol)r; if((tps.Parameter is TemplateTypeParameter || tps.Parameter is TemplateAliasParameter)) return new TypeValue(tps.Base ?? tps); if(tps.Parameter is TemplateValueParameter) return tps.ParameterValue; if(tps.Parameter is TemplateTupleParameter) return new TypeValue(tps.Base); //TODO: Are there other evaluable template parameters? } else if (r is UserDefinedType || r is PackageSymbol || r is ModuleSymbol || r is AliasedType) { if (overloads.Length > 1) { EvalError(idOrTemplateInstance, ambigousExprMsg, overloads); return null; } return new TypeValue(r); } else if (r is MemberSymbol) { var mr = (MemberSymbol)r; // If we've got a function here, execute it if (mr.Definition is DMethod) { if (ImplicitlyExecute) { if (overloads.Length > 1){ EvalError(idOrTemplateInstance, ambigousExprMsg, overloads); return null; } return FunctionEvaluation.Execute(mr, executionArguments, ValueProvider); } return new InternalOverloadValue(overloads); } else if (mr.Definition is DVariable) { if (overloads.Length > 1) { EvalError(idOrTemplateInstance, ambigousExprMsg, overloads); return null; } return new VariableValue(mr); } } EvalError(idOrTemplateInstance, "Could neither execute nor evaluate symbol value", overloads); return null; }
public static bool IsEqual(ISymbolValue val_x1, ISymbolValue val_x2) { //TODO return val_x1 != null && val_x2 != null && val_x1.ToString() == val_x2.ToString(); }
/// <summary> /// Returns either all unfiltered and undeduced overloads of a member of a base type/value (like b from type a if the expression is a.b). /// if <param name="EvalAndFilterOverloads"></param> is false. /// If true, all overloads will be deduced, filtered and evaluated, so that (in most cases,) a one-item large array gets returned /// which stores the return value of the property function b that is executed without arguments. /// Also handles UFCS - so if filtering is wanted, the function becom /// </summary> ISemantic[] E(PostfixExpression_Access acc, ISemantic resultBase = null, bool EvalAndFilterOverloads = true, bool ResolveImmediateBaseType = true) { if (acc == null) { return(null); } var baseExpression = resultBase ?? E(acc.PostfixForeExpression); if (acc.AccessExpression is NewExpression) { /* * This can be both a normal new-Expression as well as an anonymous class declaration! */ //TODO! return(null); } AbstractType[] overloads; var optBackup = ctxt.CurrentContext.ContextDependentOptions; if (acc.AccessExpression is TemplateInstanceExpression) { if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; } var tix = (TemplateInstanceExpression)acc.AccessExpression; // Do not deduce and filter if superior expression is a method call since call arguments' types also count as template arguments! overloads = GetOverloads(tix, new[] { AbstractType.Get(baseExpression) }, EvalAndFilterOverloads); if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions = optBackup; } } else if (acc.AccessExpression is IdentifierExpression) { var id = acc.AccessExpression as IdentifierExpression; if (eval && EvalAndFilterOverloads && resultBase != null) { var staticPropResult = StaticProperties.TryEvalPropertyValue(ValueProvider, resultBase, id.ValueStringHash); if (staticPropResult != null) { return new[] { staticPropResult } } ; } if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; } overloads = TypeDeclarationResolver.ResolveFurtherTypeIdentifier(id.ValueStringHash, new[] { AbstractType.Get(baseExpression) }, ctxt, acc.AccessExpression); if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions = optBackup; } } else { if (eval) { EvalError(acc, "Invalid access expression"); return(null); } ctxt.LogError(acc, "Invalid post-dot expression"); return(null); } /* * Try to get ufcs functions at first! * * void foo(int i) {} * * class A * { * void foo(int i, int a) {} * * void bar(){ * 123.foo(23); // Not allowed! * // Anyway, if we tried to search ufcs functions AFTER searching from child to parent scope levels, * // it would return the local foo() only, not the global one..which would be an error then! * } * * Probably also worth to notice is the property syntax..are property functions rather preferred than ufcs ones? * } */ if (overloads == null || EvalAndFilterOverloads) { var oo = UFCSResolver.TryResolveUFCS(baseExpression, acc, ctxt) as AbstractType[]; if (oo != null) { int overloadsLength = overloads == null ? 0 : overloads.Length; var newArr = new AbstractType[overloadsLength + oo.Length]; if (overloadsLength != 0) { overloads.CopyTo(newArr, 0); } oo.CopyTo(newArr, overloadsLength); overloads = newArr; } } // If evaluation active and the access expression is stand-alone, return a single item only. if (EvalAndFilterOverloads && eval) { return new[] { TryDoCTFEOrGetValueRefs(overloads, acc.AccessExpression) } } ; return(overloads); } ISemantic E(PostfixExpression_Index x, ISemantic foreExpression) { if (eval) { //TODO: Access pointer arrays(?) if (foreExpression is ArrayValue) // ArrayValue must be checked first due to inheritance! { var av = foreExpression as ArrayValue; // Make $ operand available var arrLen_Backup = ValueProvider.CurrentArrayLength; ValueProvider.CurrentArrayLength = av.Elements.Length; var n = E(x.Arguments[0]) as PrimitiveValue; ValueProvider.CurrentArrayLength = arrLen_Backup; if (n == null) { EvalError(x.Arguments[0], "Returned no value"); return(null); } int i = 0; try{ i = Convert.ToInt32(n.Value); } catch { EvalError(x.Arguments[0], "Index expression must be of type int"); return(null); } if (i < 0 || i > av.Elements.Length) { EvalError(x.Arguments[0], "Index out of range - it must be between 0 and " + av.Elements.Length); return(null); } return(av.Elements[i]); } else if (foreExpression is AssociativeArrayValue) { var aa = (AssociativeArrayValue)foreExpression; var key = E(x.Arguments[0]); if (key == null) { EvalError(x.Arguments[0], "Returned no value"); return(null); } ISymbolValue val = null; foreach (var kv in aa.Elements) { if (kv.Key.Equals(key)) { return(kv.Value); } } EvalError(x, "Could not find key '" + val + "'"); return(null); } EvalError(x.PostfixForeExpression, "Invalid index expression base value type", foreExpression); return(null); } else { foreExpression = DResolver.StripMemberSymbols(AbstractType.Get(foreExpression)); if (foreExpression is AssocArrayType) { var ar = foreExpression as AssocArrayType; /* * myType_Array[0] -- returns TypeResult myType * return the value type of a given array result */ //TODO: Handle opIndex overloads return(new ArrayAccessSymbol(x, ar.ValueType)); } /* * int* a = new int[10]; * * a[0] = 12; */ else if (foreExpression is PointerType) { return((foreExpression as PointerType).Base); } //return new ArrayAccessSymbol(x,((PointerType)foreExpression).Base); else if (foreExpression is DTuple) { var tt = foreExpression as DTuple; if (x.Arguments != null && x.Arguments.Length != 0) { var idx = EvaluateValue(x.Arguments[0], ctxt) as PrimitiveValue; if (idx == null || !DTokens.BasicTypes_Integral[idx.BaseTypeToken]) { ctxt.LogError(x.Arguments[0], "Index expression must evaluate to integer value"); } else if (idx.Value > (decimal)Int32.MaxValue || (int)idx.Value >= tt.Items.Length || (int)idx.Value < 0) { ctxt.LogError(x.Arguments[0], "Index number must be a value between 0 and " + tt.Items.Length); } else { return(tt.Items[(int)idx.Value]); } } } ctxt.LogError(new ResolutionError(x, "Invalid base type for index expression")); } return(null); } ISemantic E(PostfixExpression_Slice x, ISemantic foreExpression) { if (!eval) { return(foreExpression); // Still of the array's type. } if (!(foreExpression is ArrayValue)) { EvalError(x.PostfixForeExpression, "Must be an array"); return(null); } var ar = (ArrayValue)foreExpression; var sl = (PostfixExpression_Slice)x; // If the [ ] form is used, the slice is of the entire array. if (sl.FromExpression == null && sl.ToExpression == null) { return(foreExpression); } // Make $ operand available var arrLen_Backup = ValueProvider.CurrentArrayLength; ValueProvider.CurrentArrayLength = ar.Elements.Length; var bound_lower = E(sl.FromExpression) as PrimitiveValue; var bound_upper = E(sl.ToExpression) as PrimitiveValue; ValueProvider.CurrentArrayLength = arrLen_Backup; if (bound_lower == null || bound_upper == null) { EvalError(bound_lower == null ? sl.FromExpression : sl.ToExpression, "Must be of an integral type"); return(null); } int lower = -1, upper = -1; try { lower = Convert.ToInt32(bound_lower.Value); upper = Convert.ToInt32(bound_upper.Value); } catch { EvalError(lower != -1 ? sl.FromExpression : sl.ToExpression, "Boundary expression must base an integral type"); return(null); } if (lower < 0) { EvalError(sl.FromExpression, "Lower boundary must be greater than 0"); return(null); } if (lower >= ar.Elements.Length) { EvalError(sl.FromExpression, "Lower boundary must be smaller than " + ar.Elements.Length); return(null); } if (upper < lower) { EvalError(sl.ToExpression, "Upper boundary must be greater than " + lower); return(null); } if (upper >= ar.Elements.Length) { EvalError(sl.ToExpression, "Upper boundary must be smaller than " + ar.Elements.Length); return(null); } var rawArraySlice = new ISymbolValue[upper - lower]; int j = 0; for (int i = lower; i < upper; i++) { rawArraySlice[j++] = ar.Elements[i]; } return(new ArrayValue(ar.RepresentedType as ArrayType, rawArraySlice)); } ISemantic E(PostfixExpression_Increment x, ISemantic foreExpression) { // myInt++ is still of type 'int' if (!eval) { return(foreExpression); } if (resolveConstOnly) { EvalError(new NoConstException(x)); } // Must be implemented anyway regarding ctfe return(null); } ISemantic E(PostfixExpression_Decrement x, ISemantic foreExpression) { if (!eval) { return(foreExpression); } if (resolveConstOnly) { EvalError(new NoConstException(x)); } // Must be implemented anyway regarding ctfe return(null); } } }
public static AbstractType ResolveKey(ArrayDecl ad, out int fixedArrayLength, out ISymbolValue keyVal, ResolutionContext ctxt) { keyVal = null; fixedArrayLength = -1; AbstractType keyType = null; if (ad.KeyExpression != null) { //TODO: Template instance expressions? var id_x = ad.KeyExpression as IdentifierExpression; if (id_x != null && id_x.IsIdentifier) { var id = new IdentifierDeclaration((string)id_x.Value) { Location = id_x.Location, EndLocation = id_x.EndLocation }; keyType = TypeDeclarationResolver.ResolveSingle(id, ctxt); if (keyType != null) { var tt = DResolver.StripAliasSymbol(keyType) as MemberSymbol; if (tt == null || !(tt.Definition is DVariable) || ((DVariable)tt.Definition).Initializer == null) { return(keyType); } } } try { keyVal = Evaluation.EvaluateValue(ad.KeyExpression, ctxt); if (keyVal != null) { // Take the value's type as array key type keyType = keyVal.RepresentedType; // It should be mostly a number only that points out how large the final array should be var pv = Evaluation.GetVariableContents(keyVal, new StandardValueProvider(ctxt)) as PrimitiveValue; if (pv != null) { fixedArrayLength = System.Convert.ToInt32(pv.Value); if (fixedArrayLength < 0) { ctxt.LogError(ad, "Invalid array size: Length value must be greater than 0"); } } //TODO Is there any other type of value allowed? } } catch { } } else { var t = Resolve(ad.KeyType, ctxt); ctxt.CheckForSingleResult(t, ad.KeyType); if (t != null && t.Length != 0) { return(t[0]); } } return(keyType); }
public ISymbolValue Visit(AssignExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); //TODO this.rValue = null; return null; }
public bool Equals(ISymbolValue other) { return(false); }
public TemplateParameterSymbol(TemplateParameter tpn, ISemantic typeOrValue, ISyntaxRegion paramIdentifier = null) : base(tpn != null ? tpn.Representation : null, AbstractType.Get(typeOrValue), paramIdentifier) { this.Parameter = tpn; this.ParameterValue = typeOrValue as ISymbolValue; }
public ISymbolValue Visit(PostfixExpression_Slice x) { var foreExpression = EvalForeExpression(x); if (!(foreExpression is ArrayValue)) { EvalError(x.PostfixForeExpression, "Must be an array"); return(null); } var ar = (ArrayValue)foreExpression; var sl = (PostfixExpression_Slice)x; // If the [ ] form is used, the slice is of the entire array. if (sl.FromExpression == null && sl.ToExpression == null) { return(foreExpression); } // Make $ operand available var arrLen_Backup = ValueProvider.CurrentArrayLength; var len = ar.Length; ValueProvider.CurrentArrayLength = len; var bound_lower = sl.FromExpression != null?sl.FromExpression.Accept(this) as PrimitiveValue : null; var bound_upper = sl.ToExpression != null?sl.ToExpression.Accept(this) as PrimitiveValue : null; ValueProvider.CurrentArrayLength = arrLen_Backup; if (bound_lower == null || bound_upper == null) { EvalError(bound_lower == null ? sl.FromExpression : sl.ToExpression, "Must be of an integral type"); return(null); } int lower = -1, upper = -1; try { lower = Convert.ToInt32(bound_lower.Value); upper = Convert.ToInt32(bound_upper.Value); } catch { EvalError(lower != -1 ? sl.FromExpression : sl.ToExpression, "Boundary expression must base an integral type"); return(null); } if (lower < 0) { EvalError(sl.FromExpression, "Lower boundary must be greater than 0"); return(new NullValue(ar.RepresentedType)); } if (lower >= len && len > 0) { EvalError(sl.FromExpression, "Lower boundary must be smaller than " + len); return(new NullValue(ar.RepresentedType)); } if (upper < lower) { EvalError(sl.ToExpression, "Upper boundary must be greater than " + lower); return(new NullValue(ar.RepresentedType)); } else if (upper > len) { EvalError(sl.ToExpression, "Upper boundary must be smaller than " + len); return(new NullValue(ar.RepresentedType)); } if (ar.IsString) { return(new ArrayValue(ar.RepresentedType as ArrayType, ar.StringValue.Substring(lower, upper - lower))); } var rawArraySlice = new ISymbolValue[upper - lower]; int j = 0; for (int i = lower; i < upper; i++) { rawArraySlice[j++] = ar.Elements[i]; } return(new ArrayValue(ar.RepresentedType as ArrayType, rawArraySlice)); }
public abstract void Set(AbstractSymbolValueProvider vp, ISymbolValue value);
public bool Equals(ISymbolValue other) { throw new NotImplementedException(); }
public AssocArrayPointer(DVariable accessedArray, AssocArrayType arrayType, ISymbolValue accessedItemKey) : base(new MemberSymbol(accessedArray, arrayType, null)) { Key = accessedItemKey; }
public static bool IsFalseZeroOrNull(ISymbolValue v) { var pv = v as PrimitiveValue; if (pv != null) try { return pv.Value == 0m; } catch { } else return v is NullValue; return v != null; }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { vp[Variable] = value; }
/// <summary> /// Evaluates the identifier/template instance as usual. /// If the id points to a variable, the initializer/dynamic value will be evaluated using its initializer. /// /// If ImplicitlyExecute is false but value evaluation is switched on, an InternalOverloadValue-object will be returned /// that keeps all overloads passed via 'overloads' /// </summary> ISemantic TryDoCTFEOrGetValueRefs(AbstractType[] overloads, IExpression idOrTemplateInstance, bool ImplicitlyExecute = true, ISymbolValue[] executionArguments=null) { if (overloads == null || overloads.Length == 0) throw new EvaluationException(idOrTemplateInstance, "No symbols found"); var r = overloads[0]; var ex = new EvaluationException(idOrTemplateInstance, "Ambiguous expression", overloads); if (r is MemberSymbol) { var mr = (MemberSymbol)r; // If we've got a function here, execute it if (mr.Definition is DMethod) { if (ImplicitlyExecute) { if (overloads.Length > 1) throw ex; return FunctionEvaluation.Execute((DMethod)mr.Definition, executionArguments, ValueProvider); } return new InternalOverloadValue(overloads, idOrTemplateInstance); } else if (mr.Definition is DVariable) { if (overloads.Length > 1) throw ex; return new VariableValue((DVariable)mr.Definition, mr.Base, idOrTemplateInstance); } } else if (r is UserDefinedType) { if (overloads.Length > 1) throw ex; return new TypeValue(r, idOrTemplateInstance); } return null; }
public ISymbolValue Visit(EqualExpression x) { var lValue = this.lValue ?? (x.LeftOperand != null ? x.LeftOperand.Accept(this) : null); var rValue = this.rValue ?? (x.RightOperand != null ? x.RightOperand.Accept(this) : null); this.lValue = null; this.rValue = null; var l = TryGetValue(lValue); var r = TryGetValue(rValue); var isEq = SymbolValueComparer.IsEqual(l, r); return new PrimitiveValue(x.OperatorToken == DTokens.Equal ? isEq : !isEq, x); }
public abstract void Set(AbstractSymbolValueProvider vp, ISymbolValue value);
public static bool IsFalseZeroOrNull(ISymbolValue v) { var pv = v as PrimitiveValue; if (pv != null) try { return !Convert.ToBoolean(pv.Value); } catch { } else return v is NullValue; return v != null; }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { if(vp != null && vp.ev != null) vp.ev.EvalError(null,"Cannot assign a value to a static property.", new[]{this, value}); //TODO: What about array.length? }
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 override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { vp[Variable] = value; }
public ISymbolValue Visit(PostfixExpression_Index x) { var foreExpression = EvalForeExpression(x); //TODO: Access pointer arrays(?) if (foreExpression is ArrayValue) // ArrayValue must be checked first due to inheritance! { var av = foreExpression as ArrayValue; // Make $ operand available var arrLen_Backup = ValueProvider.CurrentArrayLength; ValueProvider.CurrentArrayLength = av.Elements.Length; var n = x.Arguments.Length > 0 && x.Arguments[0] != null ? x.Arguments[0].Accept(this) as PrimitiveValue : null; ValueProvider.CurrentArrayLength = arrLen_Backup; if (n == null) { EvalError(x.Arguments[0], "Returned no value"); return(null); } int i = 0; try { i = Convert.ToInt32(n.Value); } catch { EvalError(x.Arguments[0], "Index expression must be of type int"); return(null); } if (i < 0 || i > av.Elements.Length) { EvalError(x.Arguments[0], "Index out of range - it must be between 0 and " + av.Elements.Length); return(null); } return(av.Elements[i]); } else if (foreExpression is AssociativeArrayValue) { var aa = (AssociativeArrayValue)foreExpression; var key = x.Arguments.Length > 0 && x.Arguments[0] != null ? x.Arguments[0].Accept(this) as PrimitiveValue : null; if (key == null) { EvalError(x.Arguments[0], "Returned no value"); return(null); } ISymbolValue val = null; foreach (var kv in aa.Elements) { if (kv.Key.Equals(key)) { return(kv.Value); } } EvalError(x, "Could not find key '" + val + "'"); return(null); } //TODO: myClassWithAliasThis[0] -- Valid!! EvalError(x.PostfixForeExpression, "Invalid index expression base value type", foreExpression); return(null); }
public void Visit(ReturnStatement returnStatement) { returnedValue = Evaluation.EvaluateValue(returnStatement.ReturnExpression, vp); }
public virtual bool Equals(ISymbolValue other) { return(SymbolValueComparer.IsEqual(this, other)); }
public AssocArrayPointer(MemberSymbol assocArrayVariable, ISymbolValue accessedItemKey) : base(assocArrayVariable) { Key = accessedItemKey; }
public TemplateParameterSymbol(TemplateParameter tpn, ISemantic typeOrValue, ISyntaxRegion paramIdentifier = null) : base(tpn != null ? tpn.Representation : null, AbstractType.Get(typeOrValue), paramIdentifier) { this.Parameter = tpn; this.ParameterValue = typeOrValue as ISymbolValue; }
public AssocArrayPointer(DVariable accessedArray, AssocArrayType arrayType, ISymbolValue accessedItemKey) : base(new MemberSymbol(accessedArray, arrayType,null)) { Key = accessedItemKey; }
/// <summary> /// Removes all variable references by resolving them via the given value provider. /// Useful when only the value is of interest, not its container or other things. /// </summary> public static ISymbolValue GetVariableContents(ISymbolValue v, AbstractSymbolValueProvider vp) { while (v is VariableValue) v = vp[(v as VariableValue).Variable]; return v; }
public override void Set(AbstractSymbolValueProvider vp, ISymbolValue value) { var oldV = vp[Variable]; if (oldV is AssociativeArrayValue) { if (Key != null) { var aa = (AssociativeArrayValue)oldV; int itemToReplace = -1; for (int i = 0; i < aa.Elements.Count; i++) if (SymbolValueComparer.IsEqual(aa.Elements[i].Key, Key)) { itemToReplace = i; break; } // If we haven't found a matching key, add it to the array var newElements = new KeyValuePair<ISymbolValue, ISymbolValue>[aa.Elements.Count + (itemToReplace == -1 ? 1 : 0)]; aa.Elements.CopyTo(newElements, 0); if (itemToReplace != -1) newElements[itemToReplace] = new KeyValuePair<ISymbolValue, ISymbolValue>(newElements[itemToReplace].Key, value); else newElements[newElements.Length - 1] = new KeyValuePair<ISymbolValue, ISymbolValue>(Key, value); // Finally, make a new associative array containing the new elements vp[Variable] = new AssociativeArrayValue(aa.RepresentedType as AssocArrayType, newElements); } else{ if(vp.ev !=null) vp.ev.EvalError(null,"Key expression must not be null", Key); } } else{ if(vp.ev != null) vp.ev.EvalError(null,"Type of accessed item must be an associative array", oldV); } }