Beispiel #1
0
        public ISymbolValue Visit(TraitsExpression te)
        {
            switch (te.Keyword)
            {
            case "":
            case null:
                return(null);

            case "hasMember":
                bool ret           = false;
                var  optionsBackup = ctxt.ContextIndependentOptions;
                ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes;

                AbstractType t;
                var          pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider);

                if (pfa != null && t != null)
                {
                    ignoreErrors = true;
                    ret          = EvalPostfixAccessExpression(this, ctxt, pfa, t, false) != null;
                    ignoreErrors = false;
                }
                ctxt.ContextIndependentOptions = optionsBackup;
                return(new PrimitiveValue(ret, te));


            case "identifier":
                if (te.Arguments != null && te.Arguments.Length == 1)
                {
                    return(new ArrayValue(GetStringType(), te.Arguments[0].ToString()));
                }
                break;


            case "getMember":
                pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider);

                if (pfa == null || t == null)
                {
                    break;
                }

                var vs = EvalPostfixAccessExpression(this, ctxt, pfa, t, ValueProvider: ValueProvider);
                if (vs == null || vs.Length == 0)
                {
                    return(null);
                }
                return(vs[0]);


            case "getOverloads":
                optionsBackup = ctxt.ContextIndependentOptions;
                ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes;

                pfa = ExpressionTypeEvaluation.prepareMemberTraitExpression(ctxt, te, out t, ValueProvider);

                if (pfa != null && t != null)
                {
                    vs = EvalPostfixAccessExpression(this, ctxt, pfa, t);
                }
                else
                {
                    vs = null;
                }

                ctxt.ContextIndependentOptions = optionsBackup;

                return(new TypeValue(new DTuple(te, vs)));


            case "getProtection":
                optionsBackup = ctxt.ContextIndependentOptions;
                ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes;

                var prot = "public";

                if (te.Arguments == null || te.Arguments.Length != 1 || te.Arguments[0] == null)
                {
                    EvalError(te, "First trait argument must be a symbol identifier");
                }
                else
                {
                    t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[0]);

                    if (t is DSymbol)
                    {
                        var dn = (t as DSymbol).Definition;

                        if (dn.ContainsAttribute(DTokens.Private))
                        {
                            prot = "private";
                        }
                        else if (dn.ContainsAttribute(DTokens.Protected))
                        {
                            prot = "protected";
                        }
                        else if (dn.ContainsAttribute(DTokens.Package))
                        {
                            prot = "package";
                        }
                        else if (dn.ContainsAttribute(DTokens.Export))
                        {
                            prot = "export";
                        }
                    }
                    else
                    {
                        EvalError(te, "First argument must evaluate to an existing code symbol");
                    }
                }

                ctxt.ContextIndependentOptions = optionsBackup;
                return(new ArrayValue(GetStringType(), prot));

            case "getVirtualFunctions":
                break;

            case "getVirtualMethods":
                break;

            case "parent":
                break;

            case "classInstanceSize":
                break;

            case "allMembers":
                break;

            case "derivedMembers":
                break;

            case "isSame":
                ret = false;

                if (te.Arguments == null || te.Arguments.Length < 2)
                {
                    EvalError(te, "isSame requires two arguments to compare");
                }
                else
                {
                    t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[0]);

                    if (t != null)
                    {
                        var t2 = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, te.Arguments[1]);

                        if (t2 != null)
                        {
                            ret = Resolver.ResultComparer.IsEqual(t, t2);
                        }
                    }
                }

                return(new PrimitiveValue(ret, te));

            case "compiles":
                ret = false;

                if (te.Arguments != null)
                {
                    foreach (var arg in te.Arguments)
                    {
                        ret = arg == null || ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, arg) != null;

                        if (!ret)
                        {
                            break;
                        }
                    }
                }

                return(new PrimitiveValue(ret, te));
            }

            #region isXYZ-traits
            if (te.Keyword.StartsWith("is"))
            {
                var optionsBackup = ctxt.ContextIndependentOptions;
                ctxt.ContextIndependentOptions = ResolutionOptions.IgnoreAllProtectionAttributes;
                bool ret = false;

                if (te.Arguments != null)
                {
                    foreach (var arg in te.Arguments)
                    {
                        var t = ExpressionTypeEvaluation.ResolveTraitArgument(ctxt, arg);

                        bool tested = true;

                        switch (te.Keyword)
                        {
                        case "isVirtualFunction":
                        case "isVirtualMethod":
                            var ms = t as MemberSymbol;
                            if (ms == null || !(ms.Definition is DMethod))
                            {
                                break;
                            }

                            var dm = ms.Definition as DMethod;
                            var dc = dm.Parent as DClassLike;
                            if (dc != null && dc.ClassType != DTokens.Struct)
                            {
                                bool includeFinalNonOverridingMethods = te.Keyword == "isVirtualFunction";
                                ret = !dm.ContainsAttribute(includeFinalNonOverridingMethods ? (byte)0 : DTokens.Final, DTokens.Static);
                            }
                            break;

                        case "isAbstractFunction":
                            ms = t as MemberSymbol;

                            ret = ms != null &&
                                  ms.Definition is DMethod &&
                                  ms.Definition.ContainsAttribute(DTokens.Abstract);
                            break;

                        case "isFinalFunction":
                            ms = t as MemberSymbol;

                            if (ms != null && ms.Definition is DMethod)
                            {
                                ret = ms.Definition.ContainsAttribute(DTokens.Abstract) ||
                                      (ms.Definition.Parent is DClassLike && (ms.Definition.Parent as DClassLike).ContainsAttribute(DTokens.Final));
                            }
                            break;

                        case "isStaticFunction":
                            ms = t as MemberSymbol;

                            ret = ms != null && ms.Definition is DMethod && ms.Definition.IsStatic;
                            break;

                        case "isRef":
                            ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Ref);
                            break;

                        case "isOut":
                            ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Out);
                            break;

                        case "isLazy":
                            ret = t is MemberSymbol && (t as MemberSymbol).Definition.ContainsAttribute(DTokens.Lazy);
                            break;

                        default:
                            tested = false;
                            break;
                        }

                        t = DResolver.StripMemberSymbols(t);

                        if (!tested)
                        {
                            switch (te.Keyword)
                            {
                            case "isArithmetic":
                                var pt = t as PrimitiveType;
                                ret = pt != null && (
                                    DTokens.IsBasicType_Integral(pt.TypeToken) ||
                                    DTokens.IsBasicType_FloatingPoint(pt.TypeToken));
                                break;

                            case "isFloating":
                                pt  = t as PrimitiveType;
                                ret = pt != null && DTokens.IsBasicType_FloatingPoint(pt.TypeToken);
                                break;

                            case "isIntegral":
                                pt  = t as PrimitiveType;
                                ret = pt != null && DTokens.IsBasicType_Integral(pt.TypeToken);
                                break;

                            case "isScalar":
                                pt  = t as PrimitiveType;
                                ret = pt != null && DTokens.IsBasicType(pt.TypeToken);
                                break;

                            case "isUnsigned":
                                pt  = t as PrimitiveType;
                                ret = pt != null && DTokens.IsBasicType_Unsigned(pt.TypeToken);
                                break;

                            case "isAbstractClass":
                                ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Abstract);
                                break;

                            case "isFinalClass":
                                ret = t is ClassType && (t as ClassType).Definition.ContainsAttribute(DTokens.Final);
                                break;

                            case "isAssociativeArray":
                                ret = t is AssocArrayType && !(t is ArrayType);
                                break;

                            case "isStaticArray":
                                ret = t is ArrayType && (t as ArrayType).IsStaticArray;
                                break;
                            }
                        }

                        if (!ret)
                        {
                            break;
                        }
                    }
                }

                ctxt.ContextIndependentOptions = optionsBackup;
                return(new PrimitiveValue(ret, te));
            }
            else
            {
                EvalError(te, "Illegal trait token");
                return(null);
            }
            #endregion
        }