public override void Visit(TraitsExpression x) { if (x.Keyword == DTokens.IncompleteId) { prv = new TraitsExpressionCompletionProvider(cdgen); halt = true; } else { base.Visit(x); } }
/// <summary> /// Used when evaluating traits. /// Evaluates the first argument to <param name="t">t</param>, /// takes the second traits argument, tries to evaluate it to a string, and puts it + the first arg into an postfix_access expression /// </summary> PostfixExpression_Access prepareMemberTraitExpression(TraitsExpression te, out AbstractType t) { if (te.Arguments != null && te.Arguments.Length == 2) { var tEx = te.Arguments[0]; t = DResolver.StripMemberSymbols(E(tEx, te)); if (t == null) { EvalError(te, "First argument didn't resolve to a type"); } else if (te.Arguments[1].AssignExpression != null) { var litEx = te.Arguments[1].AssignExpression; var eval_Backup = eval; eval = true; var v = E(litEx); eval = eval_Backup; if (v is ArrayValue && (v as ArrayValue).IsString) { var av = v as ArrayValue; // Mock up a postfix_access expression to ensure static properties & ufcs methods are checked either return(new PostfixExpression_Access { PostfixForeExpression = tEx.AssignExpression ?? new TypeDeclarationExpression(tEx.Type), AccessExpression = new IdentifierExpression(av.StringValue) { Location = litEx.Location, EndLocation = litEx.EndLocation }, EndLocation = litEx.EndLocation }); } else { EvalError(te.Arguments[1].AssignExpression, "Second traits argument must evaluate to a string literal", v); } } else { EvalError(te, "Second traits argument must be an expression"); } } t = null; return(null); }
AbstractType E(TraitsArgument arg, TraitsExpression te) { if (arg.Type != null) { return(TypeDeclarationResolver.ResolveSingle(arg.Type, ctxt)); } else if (arg.AssignExpression != null) { return(DResolver.StripAliasSymbol(EvaluateType(arg.AssignExpression, ctxt))); } else { EvalError(te, "Argument must be a type or an expression!"); return(null); } }
public void Visit(TraitsExpression x) { }
IExpression TraitsExpression() { Expect(__traits); var ce = new TraitsExpression() { Location=t.Location}; if(Expect(OpenParenthesis)) { if (Expect (Identifier)) ce.Keyword = t.Value; else if (IsEOF) ce.Keyword = DTokens.IncompleteId; var al = new List<TraitsArgument>(); while (laKind == Comma) { Step(); if (IsAssignExpression()) al.Add(new TraitsArgument(AssignExpression())); else al.Add(new TraitsArgument(Type())); } Expect (CloseParenthesis); if(al.Count != 0) ce.Arguments = al.ToArray(); } ce.EndLocation = t.EndLocation; return ce; }
ISemantic E(TraitsExpression te) { // TODO: Return either bools, strings, array (pointers) to members or stuff return null; }
ISemantic E(TraitsExpression te) { // TODO: Return either bools, strings, array (pointers) to members or stuff return(null); }
/// <summary> /// Used when evaluating traits. /// Evaluates the first argument to <param name="t">t</param>, /// takes the second traits argument, tries to evaluate it to a string, and puts it + the first arg into an postfix_access expression /// </summary> internal static PostfixExpression_Access prepareMemberTraitExpression(ResolutionContext ctxt, TraitsExpression te, out AbstractType t, AbstractSymbolValueProvider vp = null) { if (te.Arguments != null && te.Arguments.Length == 2) { var tEx = te.Arguments[0]; t = DResolver.StripMemberSymbols(ResolveTraitArgument(ctxt, tEx)); if (t == null) { ctxt.LogError(te, "First argument didn't resolve to a type"); } else if (te.Arguments[1].AssignExpression != null) { var litEx = te.Arguments[1].AssignExpression; var v = vp != null?Evaluation.EvaluateValue(litEx, vp) : Evaluation.EvaluateValue(litEx, ctxt); if (v is ArrayValue && (v as ArrayValue).IsString) { var av = v as ArrayValue; // Mock up a postfix_access expression to ensure static properties & ufcs methods are checked either return(new PostfixExpression_Access { PostfixForeExpression = tEx.AssignExpression ?? new TypeDeclarationExpression(tEx.Type), AccessExpression = new IdentifierExpression(av.StringValue) { Location = litEx.Location, EndLocation = litEx.EndLocation }, EndLocation = litEx.EndLocation }); } else { ctxt.LogError(litEx, "Second traits argument must evaluate to a string literal"); } } else { ctxt.LogError(te, "Second traits argument must be an expression"); } } t = null; return(null); }
public override void Visit(TraitsExpression x) { if(x.Keyword == DTokens.IncompleteId) { prv = new TraitsExpressionCompletionProvider(cdgen); halt = true; } else base.Visit (x); }
IExpression TraitsExpression() { Expect(__traits); var ce = new TraitsExpression() { Location=t.Location}; LastParsedObject = ce; Expect(OpenParenthesis); if(Expect(Identifier)) ce.Keyword = t.Value; var al = new List<TraitsArgument>(); while (laKind == Comma) { Step(); if (IsAssignExpression()) al.Add(new TraitsArgument(){AssignExpression= AssignExpression()}); else al.Add(new TraitsArgument(){Type= Type()}); } Expect(CloseParenthesis); ce.EndLocation = t.EndLocation; return ce; }
IExpression TraitsExpression(IBlockNode scope) { Expect(__traits); var ce = new TraitsExpression() { Location=t.Location}; if(Expect(OpenParenthesis)) { if (Expect (Identifier)) ce.Keyword = t.Value; else if (IsEOF) ce.Keyword = DTokens.IncompleteId; var al = new List<TraitsArgument>(); var weakTypeParsingBackup = AllowWeakTypeParsing; while (laKind == Comma) { Step(); Lexer.PushLookAheadBackup (); AllowWeakTypeParsing = true; var td = Type (scope); AllowWeakTypeParsing = false; if (td != null && (laKind == Comma || laKind == CloseParenthesis || IsEOF)) { Lexer.PopLookAheadBackup (); al.Add (new TraitsArgument(td)); continue; } Lexer.RestoreLookAheadBackup (); al.Add(new TraitsArgument(AssignExpression(scope))); } AllowWeakTypeParsing = weakTypeParsingBackup; Expect (CloseParenthesis); if(al.Count != 0) ce.Arguments = al.ToArray(); } ce.EndLocation = t.EndLocation; return ce; }
AbstractType E(TraitsArgument arg, TraitsExpression te) { if(arg.Type != null) { return TypeDeclarationResolver.ResolveSingle(arg.Type, ctxt); } else if(arg.AssignExpression != null) { return DResolver.StripAliasSymbol(EvaluateType(arg.AssignExpression, ctxt)); } else { EvalError(te, "Argument must be a type or an expression!"); return null; } }
/// <summary> /// Used when evaluating traits. /// Evaluates the first argument to <param name="t">t</param>, /// takes the second traits argument, tries to evaluate it to a string, and puts it + the first arg into an postfix_access expression /// </summary> PostfixExpression_Access prepareMemberTraitExpression(TraitsExpression te,out AbstractType t) { if(te.Arguments != null && te.Arguments.Length == 2) { var tEx = te.Arguments[0]; t = DResolver.StripMemberSymbols(E(tEx,te)); if(t == null) EvalError(te, "First argument didn't resolve to a type"); else if(te.Arguments[1].AssignExpression != null) { var litEx = te.Arguments[1].AssignExpression; var eval_Backup = eval; eval = true; var v = E(litEx); eval = eval_Backup; if(v is ArrayValue && (v as ArrayValue).IsString) { var av = v as ArrayValue; // Mock up a postfix_access expression to ensure static properties & ufcs methods are checked either return new PostfixExpression_Access{ PostfixForeExpression = tEx.AssignExpression ?? new TypeDeclarationExpression(tEx.Type), AccessExpression = new IdentifierExpression(av.StringValue) { Location = litEx.Location, EndLocation = litEx.EndLocation}, EndLocation = litEx.EndLocation }; } else EvalError(te.Arguments[1].AssignExpression, "Second traits argument must evaluate to a string literal", v); } else EvalError(te, "Second traits argument must be an expression"); } t = null; return null; }
ISemantic E(TraitsExpression te) { switch(te.Keyword) { case "": case null: return null; case "hasMember": if(!eval) return new PrimitiveType(DTokens.Bool, 0); bool ret = false; var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; AbstractType t; var pfa = prepareMemberTraitExpression(te, out t); if(pfa != null && t != null) { ignoreErrors = true; eval = false; ret = E(pfa, t, false) != null; eval = true; ignoreErrors = false; } ctxt.ContextIndependentOptions = optionsBackup; return new PrimitiveValue(ret, te); case "identifier": if(!eval) return GetStringType(); if(te.Arguments!=null && te.Arguments.Length == 1) return new ArrayValue(GetStringType(), te.Arguments[0].ToString()); break; case "getMember": pfa = prepareMemberTraitExpression(te, out t); if(pfa == null ||t == null) break; var vs = E(pfa,t); if(vs == null || vs.Length == 0) return null; return vs[0]; case "getOverloads": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; pfa = prepareMemberTraitExpression(te, out t); if(pfa != null && t != null) { var evalBak = eval; eval = false; vs = E(pfa,t); eval = evalBak; } else vs = null; ctxt.ContextIndependentOptions = optionsBackup; return eval ? new TypeValue(new DTuple(te, vs)) as ISemantic : new DTuple(te, vs); case "getProtection": if(!eval) return GetStringType(); optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; var prot = "public"; if(te.Arguments == null || te.Arguments.Length != 1 || te.Arguments[0] == null) EvalError(te, "First trait argument must be a symbol identifier"); else { t = E(te.Arguments[0], te); if(t is DSymbol) { var dn = (t as DSymbol).Definition; if(dn.ContainsAttribute(DTokens.Private)) prot = "private"; else if(dn.ContainsAttribute(DTokens.Protected)) prot = "protected"; else if(dn.ContainsAttribute(DTokens.Package)) prot = "package"; else if(dn.ContainsAttribute(DTokens.Export)) prot = "export"; } else EvalError(te, "First argument must evaluate to an existing code symbol"); } ctxt.ContextIndependentOptions = optionsBackup; return new ArrayValue(GetStringType(), prot); case "getVirtualFunctions": break; case "getVirtualMethods": break; case "parent": break; case "classInstanceSize": break; case "allMembers": break; case "derivedMembers": break; case "isSame": if(!eval) return new PrimitiveType(DTokens.Bool); ret = false; if(te.Arguments == null || te.Arguments.Length < 2) { EvalError(te, "isSame требует для сравнения двух элементов"); } else { t = E(te.Arguments[0], te); if(t != null) { var t2 = E(te.Arguments[1], te); if(t2 != null) ret = Resolver.ResultComparer.IsEqual(t,t2); } } return new PrimitiveValue(ret, te); case "compiles": if(!eval) return new PrimitiveType(DTokens.Bool); ret = false; if(te.Arguments != null){ foreach(var arg in te.Arguments) { ret = E(arg, te) != null; if(!ret) break; } } return new PrimitiveValue(ret, te); } #region isXYZ-traits if(te.Keyword.StartsWith("is")) { if(eval) { var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; bool ret = false; if(te.Arguments != null) foreach(var arg in te.Arguments) { var t = E(arg,te); bool tested = true; switch(te.Keyword) { case "isVirtualFunction": case "isVirtualMethod": var ms = t as MemberSymbol; if(ms==null || !(ms.Definition is DMethod)) break; var dm = ms.Definition as DMethod; var dc = dm.Parent as DClassLike; if(dc != null && dc.ClassType != DTokens.Struct) { bool includeFinalNonOverridingMethods = te.Keyword == "isVirtualFunction"; ret = !dm.ContainsAttribute(includeFinalNonOverridingMethods ? (byte)0 : DTokens.Final, DTokens.Static); } break; case "isAbstractFunction": ms = t as MemberSymbol; ret = ms!=null && ms.Definition is DMethod && ms.Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalFunction": ms = t as MemberSymbol; if( ms!=null && ms.Definition is DMethod) { ret = ms.Definition.ContainsAttribute(DTokens.Abstract) || (ms.Definition.Parent is DClassLike && (ms.Definition.Parent as DClassLike).ContainsAttribute(DTokens.Final)); } break; case "isStaticFunction": ms = t as MemberSymbol; ret = ms!=null && ms.Definition is DMethod && ms.Definition.IsStatic; break; case "isRef": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Ref); break; case "isOut": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Out); break; case "isLazy": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Lazy); break; default: tested = false; break; } t = DResolver.StripMemberSymbols(t); if(!tested) switch(te.Keyword) { case "isArithmetic": var pt = t as PrimitiveType; ret = pt != null && ( DTokens.BasicTypes_Integral[pt.TypeToken] || DTokens.BasicTypes_FloatingPoint[pt.TypeToken]); break; case "isFloating": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_FloatingPoint[pt.TypeToken]; break; case "isIntegral": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_Integral[pt.TypeToken]; break; case "isScalar": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes[pt.TypeToken]; break; case "isUnsigned": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_Unsigned[pt.TypeToken]; break; case "isAbstractClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Final); break; case "isAssociativeArray": ret = t is AssocArrayType && !(t is ArrayType); break; case "isStaticArray": ret = t is ArrayType && (t as ArrayType).IsStaticArray; break; } if(!ret) break; } ctxt.ContextIndependentOptions = optionsBackup; return new PrimitiveValue(ret, te); } else return new PrimitiveType(DTokens.Bool, 0, te); } else { if(eval) EvalError(te, "Illegal trait token"); return null; } #endregion }
public AbstractType Visit(TraitsExpression te) { PostfixExpression_Access pfa; AbstractType t; ResolutionOptions optionsBackup; switch (te.Keyword) { case "": case null: return(null); case "identifier": return(GetStringType()); case "getMember": pfa = prepareMemberTraitExpression(te, out t); if (pfa == null || t == null) { break; } var vs = Evaluation.EvalPostfixAccessExpression(this, ctxt, pfa, t); if (vs == null || vs.Length == 0) { return(null); } return(vs[0]); case "getOverloads": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; pfa = prepareMemberTraitExpression(te, out t); if (pfa != null && t != null) { vs = Evaluation.EvalPostfixAccessExpression(this, ctxt, pfa, t); } else { vs = null; } ctxt.ContextIndependentOptions = optionsBackup; return(new DTuple(te, vs)); case "getProtection": return(GetStringType()); case "getVirtualFunctions": break; case "getVirtualMethods": break; case "parent": break; case "classInstanceSize": break; case "allMembers": break; case "derivedMembers": break; case "compiles": return(new PrimitiveType(DTokens.Bool)); } if (te.Keyword.StartsWith("is") || te.Keyword.StartsWith("has")) { return(new PrimitiveType(DTokens.Bool)); } return(null); }
IExpression TraitsExpression() { Expect(__traits); var ce = new TraitsExpression() { Location=t.Location}; LastParsedObject = ce; if(Expect(OpenParenthesis)) { if(Expect(Identifier)) ce.Keyword = t.Value; var al = new List<TraitsArgument>(); while (laKind == Comma) { Step(); if (IsAssignExpression()) al.Add(new TraitsArgument(AssignExpression())); else al.Add(new TraitsArgument(Type())); } if (Expect(CloseParenthesis)) TrackerVariables.ExpectingIdentifier = false; if(al.Count != 0) ce.Arguments = al.ToArray(); } ce.EndLocation = t.EndLocation; return ce; }
PostfixExpression_Access prepareMemberTraitExpression(TraitsExpression te, out AbstractType t) { return(prepareMemberTraitExpression(ctxt, te, out t)); }
ISemantic E(TraitsExpression te) { switch (te.Keyword) { case "": case null: return(null); case "hasMember": if (!eval) { return(new PrimitiveType(DTokens.Bool, 0)); } bool ret = false; var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; AbstractType t; var pfa = prepareMemberTraitExpression(te, out t); if (pfa != null && t != null) { ignoreErrors = true; eval = false; ret = E(pfa, t, false) != null; eval = true; ignoreErrors = false; } ctxt.ContextIndependentOptions = optionsBackup; return(new PrimitiveValue(ret, te)); case "identifier": if (!eval) { return(GetStringType()); } if (te.Arguments != null && te.Arguments.Length == 1) { return(new ArrayValue(GetStringType(), te.Arguments[0].ToString())); } break; case "getMember": pfa = prepareMemberTraitExpression(te, out t); if (pfa == null || t == null) { break; } var vs = E(pfa, t); if (vs == null || vs.Length == 0) { return(null); } return(vs[0]); case "getOverloads": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; pfa = prepareMemberTraitExpression(te, out t); if (pfa != null && t != null) { var evalBak = eval; eval = false; vs = E(pfa, t); eval = evalBak; } else { vs = null; } ctxt.ContextIndependentOptions = optionsBackup; return(eval ? new TypeValue(new DTuple(te, vs)) as ISemantic : new DTuple(te, vs)); case "getProtection": if (!eval) { return(GetStringType()); } optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; var prot = "public"; if (te.Arguments == null || te.Arguments.Length != 1 || te.Arguments[0] == null) { EvalError(te, "First trait argument must be a symbol identifier"); } else { t = E(te.Arguments[0], te); if (t is DSymbol) { var dn = (t as DSymbol).Definition; if (dn.ContainsAttribute(DTokens.Private)) { prot = "private"; } else if (dn.ContainsAttribute(DTokens.Protected)) { prot = "protected"; } else if (dn.ContainsAttribute(DTokens.Package)) { prot = "package"; } else if (dn.ContainsAttribute(DTokens.Export)) { prot = "export"; } } else { EvalError(te, "First argument must evaluate to an existing code symbol"); } } ctxt.ContextIndependentOptions = optionsBackup; return(new ArrayValue(GetStringType(), prot)); case "getVirtualFunctions": break; case "getVirtualMethods": break; case "parent": break; case "classInstanceSize": break; case "allMembers": break; case "derivedMembers": break; case "isSame": if (!eval) { return(new PrimitiveType(DTokens.Bool)); } ret = false; if (te.Arguments == null || te.Arguments.Length < 2) { EvalError(te, "isSame requires two arguments to compare"); } else { t = E(te.Arguments[0], te); if (t != null) { var t2 = E(te.Arguments[1], te); if (t2 != null) { ret = Resolver.ResultComparer.IsEqual(t, t2); } } } return(new PrimitiveValue(ret, te)); case "compiles": if (!eval) { return(new PrimitiveType(DTokens.Bool)); } ret = false; if (te.Arguments != null) { foreach (var arg in te.Arguments) { ret = E(arg, te) != null; if (!ret) { break; } } } return(new PrimitiveValue(ret, te)); } #region isXYZ-traits if (te.Keyword.StartsWith("is")) { if (eval) { var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; bool ret = false; if (te.Arguments != null) { foreach (var arg in te.Arguments) { var t = E(arg, te); bool tested = true; switch (te.Keyword) { case "isVirtualFunction": case "isVirtualMethod": var ms = t as MemberSymbol; if (ms == null || !(ms.Definition is DMethod)) { break; } var dm = ms.Definition as DMethod; var dc = dm.Parent as DClassLike; if (dc != null && dc.ClassType != DTokens.Struct) { bool includeFinalNonOverridingMethods = te.Keyword == "isVirtualFunction"; ret = !dm.ContainsAttribute(includeFinalNonOverridingMethods ? (byte)0 : DTokens.Final, DTokens.Static); } break; case "isAbstractFunction": ms = t as MemberSymbol; ret = ms != null && ms.Definition is DMethod && ms.Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalFunction": ms = t as MemberSymbol; if (ms != null && ms.Definition is DMethod) { ret = ms.Definition.ContainsAttribute(DTokens.Abstract) || (ms.Definition.Parent is DClassLike && (ms.Definition.Parent as DClassLike).ContainsAttribute(DTokens.Final)); } break; case "isStaticFunction": ms = t as MemberSymbol; ret = ms != null && ms.Definition is DMethod && ms.Definition.IsStatic; break; case "isRef": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Ref); break; case "isOut": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Out); break; case "isLazy": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Lazy); break; default: tested = false; break; } t = DResolver.StripMemberSymbols(t); if (!tested) { switch (te.Keyword) { case "isArithmetic": var pt = t as PrimitiveType; ret = pt != null && ( DTokens.BasicTypes_Integral[pt.TypeToken] || DTokens.BasicTypes_FloatingPoint[pt.TypeToken]); break; case "isFloating": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_FloatingPoint[pt.TypeToken]; break; case "isIntegral": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_Integral[pt.TypeToken]; break; case "isScalar": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes[pt.TypeToken]; break; case "isUnsigned": pt = t as PrimitiveType; ret = pt != null && DTokens.BasicTypes_Unsigned[pt.TypeToken]; break; case "isAbstractClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Final); break; case "isAssociativeArray": ret = t is AssocArrayType && !(t is ArrayType); break; case "isStaticArray": ret = t is ArrayType && (t as ArrayType).IsStaticArray; break; } } if (!ret) { break; } } } ctxt.ContextIndependentOptions = optionsBackup; return(new PrimitiveValue(ret, te)); } else { return(new PrimitiveType(DTokens.Bool, 0, te)); } } else { if (eval) { EvalError(te, "Illegal trait token"); } return(null); } #endregion }
public ISymbolValue Visit(TraitsExpression te) { switch(te.Keyword) { case "": case null: return null; case "hasMember": bool ret = false; var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; AbstractType t; var pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if(pfa != null && t != null) { t.NonStaticAccess = true; ignoreErrors = true; var res = ExpressionTypeEvaluation.EvaluateType(pfa, ctxt, false); ret = res != null; ignoreErrors = false; } ctxt.ContextIndependentOptions = optionsBackup; return new PrimitiveValue(ret); case "identifier": if(te.Arguments!=null && te.Arguments.Length == 1) return new ArrayValue(GetStringType(), te.Arguments[0].ToString()); break; case "getMember": pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if(pfa == null ||t == null) break; var vs = EvalPostfixAccessExpression(this, ctxt, pfa,t, ValueProvider:ValueProvider); if(vs == null || vs.Length == 0) return null; return vs[0]; case "getOverloads": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider); if (pfa != null && t != null) vs = EvalPostfixAccessExpression(this, ctxt, pfa, t); else vs = null; ctxt.ContextIndependentOptions = optionsBackup; return new TypeValue(new DTuple(vs)); case "getProtection": optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; var prot = "public"; if(te.Arguments == null || te.Arguments.Length != 1 || te.Arguments[0] == null) EvalError(te, "First trait argument must be a symbol identifier"); else { t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt,te.Arguments[0]); if(t is DSymbol) { var dn = (t as DSymbol).Definition; if(dn.ContainsAttribute(DTokens.Private)) prot = "private"; else if(dn.ContainsAttribute(DTokens.Protected)) prot = "protected"; else if(dn.ContainsAttribute(DTokens.Package)) prot = "package"; else if(dn.ContainsAttribute(DTokens.Export)) prot = "export"; } else EvalError(te, "First argument must evaluate to an existing code symbol"); } ctxt.ContextIndependentOptions = optionsBackup; return new ArrayValue(GetStringType(), prot); case "getVirtualFunctions": break; case "getVirtualMethods": break; case "parent": break; case "classInstanceSize": break; case "allMembers": break; case "derivedMembers": break; case "isSame": ret = false; if(te.Arguments == null || te.Arguments.Length < 2) { EvalError(te, "isSame requires two arguments to compare"); } else { t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[0]); if(t != null) { var t2 = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[1]); if(t2 != null) ret = Resolver.ResultComparer.IsEqual(t,t2); } } return new PrimitiveValue(ret); case "compiles": ret = false; if(te.Arguments != null){ foreach(var arg in te.Arguments) { ret = arg == null || ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, arg) != null; if(!ret) break; } } return new PrimitiveValue(ret); } #region isXYZ-traits if(te.Keyword.StartsWith("is")) { var optionsBackup = ctxt.ContextIndependentOptions; ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes; ctxt.CurrentContext.ContextDependentOptions |= ResolutionOptions.ReturnMethodReferencesOnly; bool ret = false; if(te.Arguments != null) foreach(var arg in te.Arguments) { var t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt,arg); bool tested = true; switch(te.Keyword) { case "isVirtualFunction": case "isVirtualMethod": var ms = t as MemberSymbol; if(ms==null || !(ms.Definition is DMethod)) break; var dm = ms.Definition as DMethod; var dc = dm.Parent as DClassLike; if(dc != null && dc.ClassType != DTokens.Struct) { bool includeFinalNonOverridingMethods = te.Keyword == "isVirtualFunction"; ret = !dm.ContainsAttribute(includeFinalNonOverridingMethods ? (byte)0 : DTokens.Final, DTokens.Static); } break; case "isAbstractFunction": ms = t as MemberSymbol; ret = ms!=null && ms.Definition is DMethod && ms.Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalFunction": ms = t as MemberSymbol; if( ms!=null && ms.Definition is DMethod) { ret = ms.Definition.ContainsAttribute(DTokens.Abstract) || (ms.Definition.Parent is DClassLike && (ms.Definition.Parent as DClassLike).ContainsAttribute(DTokens.Final)); } break; case "isStaticFunction": ms = t as MemberSymbol; ret = ms!=null && ms.Definition is DMethod && ms.Definition.IsStatic; break; case "isRef": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Ref); break; case "isOut": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Out); break; case "isLazy": ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Lazy); break; default: tested = false; break; } t = DResolver.StripMemberSymbols(t); if(!tested) switch(te.Keyword) { case "isArithmetic": var pt = t as PrimitiveType; ret = pt != null && ( DTokens.IsBasicType_Integral(pt.TypeToken) || DTokens.IsBasicType_FloatingPoint(pt.TypeToken)); break; case "isFloating": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_FloatingPoint(pt.TypeToken); break; case "isIntegral": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_Integral(pt.TypeToken); break; case "isScalar": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType(pt.TypeToken); break; case "isUnsigned": pt = t as PrimitiveType; ret = pt != null && DTokens.IsBasicType_Unsigned(pt.TypeToken); break; case "isAbstractClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Abstract); break; case "isFinalClass": ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Final); break; case "isAssociativeArray": ret = t is AssocArrayType && !(t is ArrayType); break; case "isStaticArray": ret = t is ArrayType && (t as ArrayType).IsStaticArray; break; } if(!ret) break; } ctxt.ContextIndependentOptions = optionsBackup; return new PrimitiveValue(ret); } else { EvalError(te, "Illegal trait token"); return null; } #endregion }