ISemantic E(ArrayLiteralExpression arr) { if (eval) { var elements = new List <ISymbolValue>(arr.Elements.Count); //ISSUE: Type-check each item to distinguish not matching items foreach (var e in arr.Elements) { elements.Add(E(e) as ISymbolValue); } if (elements.Count == 0) { EvalError(arr, "Array literal must contain at least one element."); return(null); } return(new ArrayValue(new ArrayType(elements[0].RepresentedType, arr), elements.ToArray())); } if (arr.Elements != null && arr.Elements.Count > 0) { // Simply resolve the first element's type and take it as the array's value type var valueType = AbstractType.Get(E(arr.Elements[0])); return(new ArrayType(valueType, arr)); } ctxt.LogError(arr, "Array literal must contain at least one element."); return(null); }
public AbstractType TryDeduce(DSymbol ds, IEnumerable <ISemantic> templateArguments, ref INode returnedNode) { var cls = ds as ClassType; if (cls == null || templateArguments == null) { return(null); } var en = templateArguments.GetEnumerator(); if (!en.MoveNext()) { return(null); } returnedNode = cls.Definition; var baseClass = DResolver.StripMemberSymbols(AbstractType.Get(en.Current)) as TemplateIntermediateType; if (baseClass == null) { return(ds); } return(new ClassType(cls.Definition, ds.DeclarationOrExpressionBase, baseClass as ClassType, baseClass is InterfaceType ? new[] { baseClass as InterfaceType } : null, ds.DeducedTypes)); }
ISemantic E(CastExpression ce) { AbstractType castedType = null; if (ce.Type != null) { var castedTypes = TypeDeclarationResolver.Resolve(ce.Type, ctxt); ctxt.CheckForSingleResult(castedTypes, ce.Type); if (castedTypes != null && castedTypes.Length != 0) { castedType = castedTypes[0]; } } else { castedType = AbstractType.Get(E(ce.UnaryExpression)); if (castedType != null && ce.CastParamTokens != null && ce.CastParamTokens.Length > 0) { //TODO: Wrap resolved type with member function attributes } } return(castedType); }
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))); }
public static DNode GetResultMember(ISemantic res, bool keepAliases = false) { var t = AbstractType.Get(res); if (t == null) { return(null); } if (keepAliases) { var aliasTag = t.Tag as TypeResolution.TypeDeclarationResolver.AliasTag; if (aliasTag != null && (!(aliasTag.aliasDefinition is ImportSymbolAlias) || // Only if the import symbol alias definition was selected, go to its base (aliasTag.typeBase != null && aliasTag.aliasDefinition.NameLocation != aliasTag.typeBase.Location))) { return(aliasTag.aliasDefinition); } } if (t is DSymbol) { return(((DSymbol)res).Definition); } return(null); }
ISemantic E(AssocArrayExpression aa) { if (eval) { var elements = new List <KeyValuePair <ISymbolValue, ISymbolValue> >(); foreach (var e in aa.Elements) { var keyVal = E(e.Key) as ISymbolValue; var valVal = E(e.Value) as ISymbolValue; elements.Add(new KeyValuePair <ISymbolValue, ISymbolValue>(keyVal, valVal)); } return(new AssociativeArrayValue(new AssocArrayType(elements[0].Value.RepresentedType, elements[0].Key.RepresentedType, aa), elements)); } if (aa.Elements != null && aa.Elements.Count > 0) { var firstElement = aa.Elements[0].Key; var firstElementValue = aa.Elements[0].Value; var keyType = AbstractType.Get(E(firstElement)); var valueType = AbstractType.Get(E(firstElementValue)); return(new AssocArrayType(valueType, keyType, aa)); } return(null); }
public bool HandleDecl(TemplateTypeParameter p, ITypeDeclaration td, ISemantic rr) { if (td is IdentifierDeclaration) { return(HandleDecl(p, (IdentifierDeclaration)td, rr)); } if (TemplateInstanceHandler.IsNonFinalArgument(rr)) { foreach (var tp in this.TargetDictionary.Keys.ToList()) { if (TargetDictionary[tp] == null) { TargetDictionary[tp] = new TemplateParameterSymbol(tp, null); } } return(true); } //HACK Ensure that no information gets lost by using this function // -- getting a value but requiring an abstract type and just extract it from the value - is this correct behaviour? var at = AbstractType.Get(rr); if (td is ArrayDecl) { return(HandleDecl(p, (ArrayDecl)td, DResolver.StripMemberSymbols(at) as AssocArrayType)); } else if (td is DTokenDeclaration) { return(HandleDecl((DTokenDeclaration)td, at)); } else if (td is DelegateDeclaration) { return(HandleDecl(p, (DelegateDeclaration)td, DResolver.StripMemberSymbols(at) as DelegateType)); } else if (td is PointerDecl) { return(HandleDecl(p, (PointerDecl)td, DResolver.StripMemberSymbols(at) as PointerType)); } else if (td is MemberFunctionAttributeDecl) { return(HandleDecl(p, (MemberFunctionAttributeDecl)td, at)); } else if (td is TypeOfDeclaration) { return(HandleDecl((TypeOfDeclaration)td, at)); } else if (td is VectorDeclaration) { return(HandleDecl((VectorDeclaration)td, at)); } else if (td is TemplateInstanceExpression) { return(HandleDecl(p, (TemplateInstanceExpression)td, at)); } return(false); }
/// <summary> /// Returns false if the item has already been set before and if the already set item is not equal to 'r'. /// Inserts 'r' into the target dictionary and returns true otherwise. /// </summary> bool Set(TemplateParameter p, ISemantic r, int nameHash) { if (p == null) { if (nameHash != 0 && TargetDictionary.ExpectedParameters != null) { foreach (var tpar in TargetDictionary.ExpectedParameters) { if (tpar.NameHash == nameHash) { p = tpar; break; } } } } if (p == null) { ctxt.LogError(null, "no fitting template parameter found!"); return(false); } // void call(T)(T t) {} // call(myA) -- T is *not* myA but A, so only assign myA's type to T. if (p is TemplateTypeParameter) { var newR = Resolver.TypeResolution.DResolver.StripMemberSymbols(AbstractType.Get(r)); if (newR != null) { r = newR; } } TemplateParameterSymbol rl; if (!TargetDictionary.TryGetValue(p, out rl) || rl == null) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); return(true); } else { if (ResultComparer.IsEqual(rl.Base, r)) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); return(true); } else if (rl == null) { TargetDictionary[p] = new TemplateParameterSymbol(p, r); } // Error: Ambiguous assignment return(false); } }
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; }
/// <summary> /// Since most expressions should return a single type only, it's not needed to use this function unless you might /// want to pay attention on (illegal) multiple overloads. /// </summary> public static AbstractType[] EvaluateTypes(IExpression x, ResolverContextStack ctxt) { var t = new Evaluation(ctxt).E(x); if (t is InternalOverloadValue) { return(((InternalOverloadValue)t).Overloads); } return(new[] { AbstractType.Get(t) }); }
ISemantic E(NewExpression nex) { // http://www.d-programming-language.org/expression.html#NewExpression ISemantic[] possibleTypes = null; if (nex.Type is IdentifierDeclaration) { possibleTypes = TypeDeclarationResolver.Resolve((IdentifierDeclaration)nex.Type, ctxt, filterForTemplateArgs: false); } else { possibleTypes = TypeDeclarationResolver.Resolve(nex.Type, ctxt); } var ctors = new Dictionary <DMethod, TemplateIntermediateType>(); if (possibleTypes == null) { return(null); } foreach (var t in possibleTypes) { var ct = DResolver.StripAliasSymbol(t as AbstractType) as TemplateIntermediateType; if (ct != null && !ct.Definition.ContainsAttribute(DTokens.Abstract)) { foreach (var ctor in GetConstructors(ct)) { ctors.Add(ctor, ct); } } } MemberSymbol finalCtor = null; var kvArray = ctors.ToArray(); /* * TODO: Determine argument types and filter out ctor overloads. */ if (kvArray.Length != 0) { finalCtor = new MemberSymbol(kvArray[0].Key, kvArray[0].Value, nex); } else if (possibleTypes.Length != 0) { return(AbstractType.Get(possibleTypes[0])); } return(finalCtor); }
ISemantic E(UnaryExpression_And x) { var ptrBase = E(x.UnaryExpression); if (eval) { // Create a new pointer // } // &i -- makes an int* out of an int return(new PointerType(AbstractType.Get(ptrBase), x)); }
public static AbstractType EvaluateType(IExpression x, ResolutionContext ctxt) { var ev = new Evaluation(ctxt); ISemantic t = null; if (!Debugger.IsAttached) { try { t = ev.E(x); } catch { } } else { t = ev.E(x); } return(AbstractType.Get(t)); }
public static AbstractType Resolve(ArrayDecl ad, ResolutionContext ctxt) { var valueTypes = Resolve(ad.ValueType, ctxt); ctxt.CheckForSingleResult(valueTypes, ad); AbstractType valueType = null; AbstractType keyType = null; int fixedArrayLength = -1; if (valueTypes != null && valueTypes.Length != 0) { valueType = valueTypes[0]; } ISymbolValue val; keyType = ResolveKey(ad, out fixedArrayLength, out val, ctxt); if (keyType == null || (keyType is PrimitiveType && ((PrimitiveType)keyType).TypeToken == DTokens.Int)) { if (fixedArrayLength >= 0) { // D Magic: One might access tuple items directly in the pseudo array declaration - so stuff like Tup[0] i; becomes e.g. int i; var dtup = DResolver.StripMemberSymbols(valueType) as DTuple; if (dtup == null) { return(new ArrayType(valueType, fixedArrayLength, ad)); } if (dtup.Items != null && fixedArrayLength < dtup.Items.Length) { return(AbstractType.Get(dtup.Items [fixedArrayLength])); } else { ctxt.LogError(ad, "TypeTuple only consists of " + (dtup.Items != null ? dtup.Items.Length : 0) + " items. Can't access item at index " + fixedArrayLength); return(null); } } return(new ArrayType(valueType, ad)); } return(new AssocArrayType(valueType, keyType, ad)); }
bool HandleDecl(TemplateTypeParameter p, ITypeDeclaration td, ISemantic rr) { if (td is IdentifierDeclaration) { return(HandleDecl(p, (IdentifierDeclaration)td, rr)); } //HACK Ensure that no information gets lost by using this function // -- getting a value but requiring an abstract type and just extract it from the value - is this correct behaviour? var at = AbstractType.Get(rr); if (td is ArrayDecl) { return(HandleDecl(p, (ArrayDecl)td, at as AssocArrayType)); } else if (td is DTokenDeclaration) { return(HandleDecl((DTokenDeclaration)td, at)); } else if (td is DelegateDeclaration) { return(HandleDecl(p, (DelegateDeclaration)td, at as DelegateType)); } else if (td is PointerDecl) { return(HandleDecl(p, (PointerDecl)td, at as PointerType)); } else if (td is MemberFunctionAttributeDecl) { return(HandleDecl(p, (MemberFunctionAttributeDecl)td, at)); } else if (td is TypeOfDeclaration) { return(HandleDecl((TypeOfDeclaration)td, at)); } else if (td is VectorDeclaration) { return(HandleDecl((VectorDeclaration)td, at)); } else if (td is TemplateInstanceExpression) { return(HandleDecl(p, (TemplateInstanceExpression)td, at)); } return(false); }
/// <summary> /// Since most expressions should return a single type only, it's not needed to use this function unless you might /// want to pay attention on (illegal) multiple overloads. /// </summary> public static AbstractType[] EvaluateTypes(IExpression x, ResolutionContext ctxt) { var ev = new Evaluation(ctxt); ISemantic t = null; if (!Debugger.IsAttached) { try { t = ev.E(x); } catch { } } else { t = ev.E(x); } if (t is InternalOverloadValue) { return(((InternalOverloadValue)t).Overloads); } return(t == null ? null : new[] { AbstractType.Get(t) }); }
/// <summary> /// Returns all constructors from the given class or struct. /// If no explicit constructor given, an artificial implicit constructor method stub will be created. /// </summary> public static IEnumerable <DMethod> GetConstructors(TemplateIntermediateType ct) { bool foundExplicitCtor = false; // Simply get all constructors that have the ctor id assigned. Makin' it faster ;) var ch = ct.Definition[DMethod.ConstructorIdentifier]; if (ch != null) { foreach (var m in ch) { // Not to forget: 'this' aliases are also possible - so keep checking for m being a genuine ctor var dm = m as DMethod; if (m != null && dm.SpecialType == DMethod.MethodType.Constructor) { yield return(dm); foundExplicitCtor = true; } } } if (!foundExplicitCtor) { yield return new DMethod(DMethod.MethodType.Constructor) { Name = DMethod.ConstructorIdentifier, Parent = ct.Definition, Description = "Default constructor for " + ct.Name } } ; } ISemantic E(CastExpression ce) { AbstractType castedType = null; if (ce.Type != null) { var castedTypes = TypeDeclarationResolver.Resolve(ce.Type, ctxt); ctxt.CheckForSingleResult(castedTypes, ce.Type); if (castedTypes != null && castedTypes.Length != 0) { castedType = castedTypes[0]; } } else { castedType = AbstractType.Get(E(ce.UnaryExpression)); if (castedType != null && ce.CastParamTokens != null && ce.CastParamTokens.Length > 0) { //TODO: Wrap resolved type with member function attributes } } return(castedType); } ISemantic E(UnaryExpression_Cat x) // a = ~b; { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_Increment x) { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_Decrement x) { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_Add x) { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_Sub x) { var v = E(x.UnaryExpression); if (eval) { if (v is AbstractType) { v = DResolver.StripMemberSymbols((AbstractType)v); } if (v is PrimitiveValue) { var pv = (PrimitiveValue)v; return(new PrimitiveValue(pv.BaseTypeToken, -pv.Value, x, -pv.ImaginaryPart)); } } return(v); } ISemantic E(UnaryExpression_Not x) { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_Mul x) { return(E(x.UnaryExpression)); } ISemantic E(UnaryExpression_And x) { var ptrBase = E(x.UnaryExpression); if (eval) { // Create a new pointer // } // &i -- makes an int* out of an int return(new PointerType(AbstractType.Get(ptrBase), x)); } ISemantic E(DeleteExpression x) { if (eval) { // Reset the content of the variable } return(null); } ISemantic E(UnaryExpression_Type x) { var uat = x as UnaryExpression_Type; if (uat.Type == null) { return(null); } var types = TypeDeclarationResolver.Resolve(uat.Type, ctxt); ctxt.CheckForSingleResult(types, uat.Type); if (types != null && types.Length != 0) { var id = new IdentifierDeclaration(uat.AccessIdentifier) { EndLocation = uat.EndLocation }; // First off, try to resolve static properties var statProp = StaticPropertyResolver.TryResolveStaticProperties(types[0], uat.AccessIdentifier, ctxt, eval, id); if (statProp != null) { return(statProp); } // If it's not the case, try the conservative way var res = TypeDeclarationResolver.Resolve(id, ctxt, types); ctxt.CheckForSingleResult(res, x); if (res != null && res.Length != 0) { return(res[0]); } } return(null); } }
public AbstractType TryDeduce(DSymbol ds, IEnumerable <ISemantic> templateArguments, ref INode n) { TemplateTypeParameter tp; var t = ds as TemplateType; if (t == null) { return(null); } var orig = ds.Definition; var tupleStruct = new DClassLike(DTokens.Struct) { NameHash = ds.NameHash, Parent = orig.Parent, Location = orig.Location, EndLocation = orig.EndLocation, NameLocation = orig.NameLocation }; var ded = new Templates.DeducedTypeDictionary(tupleStruct); if (templateArguments != null) { var typeList = new List <AbstractType>(); var en = templateArguments.GetEnumerator(); if (en.MoveNext()) { var next = en.Current; int i = 0; for (; ; i++) { var fieldType = AbstractType.Get(next); if (fieldType == null) { break; } fieldType.NonStaticAccess = true; typeList.Add(fieldType); if (!en.MoveNext()) { break; } next = en.Current; if (next is ArrayValue && (next as ArrayValue).IsString) { var name = (next as ArrayValue).StringValue; var templateParamName = "_" + i.ToString(); tp = new TemplateTypeParameter(templateParamName, CodeLocation.Empty, tupleStruct); ded[tp] = new TemplateParameterSymbol(tp, fieldType); tupleStruct.Add(new DVariable { Name = name, Type = new IdentifierDeclaration(templateParamName) }); if (!en.MoveNext()) { break; } next = en.Current; } } } var tupleName = "Types"; tp = new TemplateTypeParameter(tupleName, CodeLocation.Empty, tupleStruct); ded[tp] = new TemplateParameterSymbol(tp, new DTuple(null, typeList)); tupleStruct.Add(new DVariable { NameHash = DVariable.AliasThisIdentifierHash, IsAlias = true, IsAliasThis = true, Type = new IdentifierDeclaration(tupleName) }); } n = tupleStruct; return(new StructType(tupleStruct, ds.DeclarationOrExpressionBase, ded.Count != 0 ? ded.Values : null)); //TODO: Ensure renaming and other AST-based things run properly }
public static AbstractType EvaluateType(IExpression x, ResolverContextStack ctxt) { return(AbstractType.Get(new Evaluation(ctxt).E(x))); }
public AbstractType TryDeduce(DSymbol ds, IEnumerable <ISemantic> templateArguments, ref INode n) { TemplateTypeParameter tp; var t = ds as TemplateType; if (t == null) { return(null); } var orig = ds.Definition; var tupleStruct = new DClassLike(DTokens.Struct) { NameHash = ds.NameHash, Parent = orig.Parent, Location = orig.Location, EndLocation = orig.EndLocation, NameLocation = orig.NameLocation }; var ded = new Templates.DeducedTypeDictionary(tupleStruct); var sb = new StringBuilder(); if (templateArguments != null) { var en = templateArguments.GetEnumerator(); if (en.MoveNext()) { var next = en.Current; int i = 0; for (; ; i++) { var fieldType = AbstractType.Get(next); if (fieldType == null) { break; } fieldType.NonStaticAccess = true; if (!en.MoveNext()) { break; } next = en.Current; if (next is ArrayValue && (next as ArrayValue).IsString) { var name = (next as ArrayValue).StringValue; if (!string.IsNullOrWhiteSpace(name)) { var templateParamName = "_" + i.ToString(); tp = new TemplateTypeParameter(templateParamName, CodeLocation.Empty, tupleStruct); ded[tp] = new TemplateParameterSymbol(tp, fieldType); // getter sb.Append("@property @safe ").Append(templateParamName).Append(' ').Append(name).AppendLine("() pure nothrow const {}"); // setter sb.Append("@property @safe void ").Append(name).AppendLine("(").Append(templateParamName).AppendLine(" v) pure nothrow {}"); // constants sb.Append("enum ").Append(templateParamName).Append(" ").Append(name).Append("_min = cast(").Append(templateParamName).AppendLine(") 0;"); sb.Append("enum ").Append(templateParamName).Append(" ").Append(name).Append("_max = cast(").Append(templateParamName).AppendLine(") 0;"); } if (!en.MoveNext()) { break; } } else { break; } if (!en.MoveNext()) // Skip offset { break; } next = en.Current; } } tupleStruct.Add(new DVariable { NameHash = tupleStruct.NameHash, Attributes = new List <DAttribute> { new Modifier(DTokens.Enum) }, Initializer = new IdentifierExpression(sb.ToString(), LiteralFormat.StringLiteral, LiteralSubformat.Utf8) }); } n = tupleStruct; return(new TemplateType(tupleStruct, ds.DeclarationOrExpressionBase, ded.Count != 0 ? ded.Values : null)); }
/// <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); } } }
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; } }
bool Handle(TemplateAliasParameter p, ISemantic arg) { #region Handle parameter defaults if (arg == null) { if (p.DefaultExpression != null) { var eval = Evaluation.EvaluateValue(p.DefaultExpression, ctxt); if (eval == null) { return(false); } return(Set(p, eval, 0)); } else if (p.DefaultType != null) { var res = TypeDeclarationResolver.Resolve(p.DefaultType, ctxt); if (res == null) { return(false); } bool ret = false; foreach (var r in res) { if (!Set(p, r, 0)) { ret = true; } } if (ret) { return(false); } } return(false); } #endregion #region Given argument must be a symbol - so no built-in type but a reference to a node or an expression var t = AbstractType.Get(arg); if (t == null) { return(false); } if (!(t is DSymbol)) { while (t != null) { if (t is PrimitiveType) // arg must not base on a primitive type. { return(false); } if (t is DerivedDataType) { t = ((DerivedDataType)t).Base; } else { break; } } } #endregion #region Specialization check if (p.SpecializationExpression != null) { // LANGUAGE ISSUE: Can't do anything here - dmd won't let you use MyClass!(2) though you have class MyClass(alias X:2) return(false); } else if (p.SpecializationType != null) { // ditto return(false); } #endregion return(Set(p, arg, 0)); }
public TemplateParameterSymbol(TemplateParameterNode tpn, ISemantic typeOrValue, ISyntaxRegion paramIdentifier = null) : base(tpn, AbstractType.Get(typeOrValue), paramIdentifier) { this.Parameter = tpn.TemplateParameter; this.ParameterValue = typeOrValue as ISymbolValue; }
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); }
/// <summary> /// Used for searching further identifier list parts. /// /// a.b -- nextIdentifier would be 'b' whereas <param name="resultBases">resultBases</param> contained the resolution result for 'a' /// </summary> public static AbstractType[] ResolveFurtherTypeIdentifier(string nextIdentifier, IEnumerable <AbstractType> resultBases, ResolverContextStack ctxt, object typeIdObject = null) { if ((resultBases = DResolver.StripAliasSymbols(resultBases)) == null) { return(null); } var r = new List <AbstractType>(); var nextResults = new List <AbstractType>(); foreach (var b in resultBases) { IEnumerable <AbstractType> scanResults = new[] { b }; do { foreach (var scanResult in scanResults) { // First filter out all alias and member results..so that there will be only (Static-)Type or Module results left.. if (scanResult is MemberSymbol) { var mr = (MemberSymbol)scanResult; if (mr.Base != null) { nextResults.Add(mr.Base); } } else if (scanResult is UserDefinedType) { var udt = (UserDefinedType)scanResult; var bn = udt.Definition as IBlockNode; var nodeMatches = NameScan.ScanNodeForIdentifier(bn, nextIdentifier, ctxt); ctxt.PushNewScope(bn); ctxt.CurrentContext.IntroduceTemplateParameterTypes(udt); var results = HandleNodeMatches(nodeMatches, ctxt, b, typeIdObject); if (results != null) { foreach (var res in results) { r.Add(AbstractType.Get(res)); } } ctxt.CurrentContext.RemoveParamTypesFromPreferredLocals(udt); ctxt.Pop(); } else if (scanResult is PackageSymbol) { var pack = ((PackageSymbol)scanResult).Package; IAbstractSyntaxTree accessedModule = null; if (pack.Modules.TryGetValue(nextIdentifier, out accessedModule)) { r.Add(new ModuleSymbol(accessedModule as DModule, typeIdObject as ISyntaxRegion, (PackageSymbol)scanResult)); } else if (pack.Packages.TryGetValue(nextIdentifier, out pack)) { r.Add(new PackageSymbol(pack, typeIdObject as ISyntaxRegion)); } } else if (scanResult is ModuleSymbol) { var modRes = (ModuleSymbol)scanResult; var matches = NameScan.ScanNodeForIdentifier(modRes.Definition, nextIdentifier, ctxt); var results = HandleNodeMatches(matches, ctxt, b, typeIdObject); if (results != null) { foreach (var res in results) { r.Add(AbstractType.Get(res)); } } } } scanResults = DResolver.FilterOutByResultPriority(ctxt, nextResults); nextResults = new List <AbstractType>(); }while (scanResults != null); } return(r.Count == 0 ? null : r.ToArray()); }
/// <summary> /// Returns either all unfiltered and undeduced overloads of a member of a base type/value (like b from type a if the expression is a.b). /// if <param name="EvalAndFilterOverloads"></param> is false. /// If true, all overloads will be deduced, filtered and evaluated, so that (in most cases,) a one-item large array gets returned /// which stores the return value of the property function b that is executed without arguments. /// Also handles UFCS - so if filtering is wanted, the function becom /// </summary> public static R[] EvalPostfixAccessExpression <R>(ExpressionVisitor <R> vis, ResolutionContext ctxt, PostfixExpression_Access acc, ISemantic resultBase = null, bool EvalAndFilterOverloads = true, bool ResolveImmediateBaseType = true, AbstractSymbolValueProvider ValueProvider = null) where R : class, ISemantic { if (acc == null) { return(null); } var baseExpression = resultBase ?? (acc.PostfixForeExpression != null ? acc.PostfixForeExpression.Accept(vis) as ISemantic : null); if (acc.AccessExpression is NewExpression) { /* * This can be both a normal new-Expression as well as an anonymous class declaration! */ //TODO! return(null); } AbstractType[] overloads; var optBackup = ctxt.CurrentContext.ContextDependentOptions; if (acc.AccessExpression is TemplateInstanceExpression) { if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; } var tix = (TemplateInstanceExpression)acc.AccessExpression; // Do not deduce and filter if superior expression is a method call since call arguments' types also count as template arguments! overloads = ExpressionTypeEvaluation.GetOverloads(tix, ctxt, new[] { AbstractType.Get(baseExpression) }, EvalAndFilterOverloads); if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions = optBackup; } } else if (acc.AccessExpression is IdentifierExpression) { var id = acc.AccessExpression as IdentifierExpression; if (ValueProvider != null && EvalAndFilterOverloads && baseExpression != null) { var staticPropResult = StaticProperties.TryEvalPropertyValue(ValueProvider, baseExpression, id.ValueStringHash); if (staticPropResult != null) { return new[] { (R)staticPropResult } } ; } if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.DontResolveBaseTypes; } overloads = ExpressionTypeEvaluation.GetOverloads(id, ctxt, AmbiguousType.TryDissolve(AbstractType.Get(baseExpression)), EvalAndFilterOverloads); if (!ResolveImmediateBaseType) { ctxt.CurrentContext.ContextDependentOptions = optBackup; } } else { /* * if (eval){ * EvalError(acc, "Invalid access expression"); * return null; * }*/ ctxt.LogError(acc, "Invalid post-dot expression"); return(null); } // If evaluation active and the access expression is stand-alone, return a single item only. if (EvalAndFilterOverloads && ValueProvider != null) { return new[] { (R) new Evaluation(ValueProvider).TryDoCTFEOrGetValueRefs(AmbiguousType.Get(overloads, acc.AccessExpression), acc.AccessExpression) } } ; return(overloads as R[]); } ISymbolValue EvalForeExpression(PostfixExpression ex) { return(ex.PostfixForeExpression != null?ex.PostfixForeExpression.Accept(this) : null); }
/// <summary> /// Tries to resolve a static property's name. /// Returns a result describing the theoretical member (".init"-%gt;MemberResult; ".typeof"->TypeResult etc). /// Returns null if nothing was found. /// </summary> /// <param name="InitialResult"></param> /// <returns></returns> public static MemberSymbol TryResolveStaticProperties( ISemantic InitialResult, string propertyIdentifier, ResolverContextStack ctxt = null, bool Evaluate = false, IdentifierDeclaration idContainter = null) { // If a pointer'ed type is given, take its base type if (InitialResult is PointerType) { InitialResult = ((PointerType)InitialResult).Base; } if (InitialResult == null || InitialResult is ModuleSymbol) { return(null); } INode relatedNode = null; if (InitialResult is DSymbol) { relatedNode = ((DSymbol)InitialResult).Definition; } #region init if (propertyIdentifier == "init") { var prop_Init = new DVariable { Name = "init", Description = "Initializer" }; if (relatedNode != null) { if (!(relatedNode is DVariable)) { prop_Init.Parent = relatedNode.Parent; prop_Init.Type = new IdentifierDeclaration(relatedNode.Name); } else { prop_Init.Parent = relatedNode; prop_Init.Initializer = (relatedNode as DVariable).Initializer; prop_Init.Type = relatedNode.Type; } } return(new MemberSymbol(prop_Init, DResolver.StripAliasSymbol(AbstractType.Get(InitialResult)), idContainter)); } #endregion #region sizeof if (propertyIdentifier == "sizeof") { return(new MemberSymbol(new DVariable { Name = "sizeof", Type = new DTokenDeclaration(DTokens.Int), Initializer = new IdentifierExpression(4), Description = "Size in bytes (equivalent to C's sizeof(type))" }, new PrimitiveType(DTokens.Int), idContainter)); } #endregion #region alignof if (propertyIdentifier == "alignof") { return(new MemberSymbol(new DVariable { Name = "alignof", Type = new DTokenDeclaration(DTokens.Int), Description = "Alignment size" }, new PrimitiveType(DTokens.Int), idContainter)); } #endregion #region mangleof if (propertyIdentifier == "mangleof") { return(new MemberSymbol(new DVariable { Name = "mangleof", Type = new IdentifierDeclaration("string"), Description = "String representing the ‘mangled’ representation of the type" }, getStringType(ctxt), idContainter)); } #endregion #region stringof if (propertyIdentifier == "stringof") { return(new MemberSymbol(new DVariable { Name = "stringof", Type = new IdentifierDeclaration("string"), Description = "String representing the source representation of the type" }, getStringType(ctxt), idContainter)); } #endregion #region classinfo else if (propertyIdentifier == "classinfo") { var tr = DResolver.StripMemberSymbols(AbstractType.Get(InitialResult)) as TemplateIntermediateType; if (tr is ClassType || tr is InterfaceType) { var ci = new IdentifierDeclaration("TypeInfo_Class") { InnerDeclaration = new IdentifierDeclaration("object"), ExpressesVariableAccess = true, }; var ti = TypeDeclarationResolver.Resolve(ci, ctxt); ctxt.CheckForSingleResult(ti, ci); return(new MemberSymbol(new DVariable { Name = "classinfo", Type = ci }, ti != null && ti.Length != 0?ti[0]:null, idContainter)); } } #endregion //TODO: Resolve the types of type-specific properties (floats, ints, arrays, assocarrays etc.) return(null); }