示例#1
0
 private bool Equals(RankedType other)
 {
     return(Type == other.Type && Rank == other.Rank);
 }
示例#2
0
        /// <summary> Extract the reflection rules from type <paramref name="t"/>. </summary>
        public RuleSet(Type t, Type token, Type result, int end, IReadOnlyDictionary <int, IReadOnlyList <int> > publicChildren)
        {
            PublicChildren = publicChildren;

            // Extract token names
            TokenNames  = token.GetEnumNames();
            TokenType   = token;
            EndOfStream = end;

            var maxRank         = new Dictionary <Type, int>();
            var rankedTypeId    = new Dictionary <RankedType, int>();
            var rankedTypes     = new List <RankedType>();
            var ruleId          = new List <List <int> >();
            var uncompiledRules = new List <UncompiledRule>();

            // Explore methods to find those to be compiled
            foreach (var m in t.GetMethods())
            {
                var ruleAttribute = m.GetCustomAttribute <RuleAttribute>();
                if (ruleAttribute == null)
                {
                    continue;
                }

                // Update the max-rank for this type
                int tMaxRank;
                if (!maxRank.TryGetValue(m.ReturnType, out tMaxRank) || tMaxRank < ruleAttribute.Rank)
                {
                    maxRank[m.ReturnType] = ruleAttribute.Rank;
                }

                // Get or create the RankedType and its identifier
                var rt = new RankedType(m.ReturnType, ruleAttribute.Rank);

                int rtid;
                if (!rankedTypeId.TryGetValue(rt, out rtid))
                {
                    rankedTypes.Add(rt);
                    ruleId.Add(new List <int>());
                    rankedTypeId.Add(rt, rtid = rankedTypeId.Count);
                }

                // Determine the number of optional parameters, to generate one
                // rule for each parameter combination. This includes both optional
                // terminals AND lists which allow zero elements.
                var options = m.GetParameters()
                              .Count(p =>
                                     (p.GetCustomAttribute <TerminalAttribute>()?.Optional ?? false) ||
                                     (p.GetCustomAttribute <NonTerminalAttribute>()?.Optional ?? false) ||
                                     (p.GetCustomAttribute <ListAttribute>()?.Min ?? 1) == 0);

                var combinations = 1 << options;

                // Allocate news rule (not compiled yet) and bind to RankedType
                for (var i = 0; i < combinations; ++i)
                {
                    var rid = uncompiledRules.Count + TokenNames.Count;
                    uncompiledRules.Add(new UncompiledRule(m, i));
                    ruleId[rtid].Add(rid);
                }
            }

            MaxRank      = maxRank;
            RankedTypeId = rankedTypeId;
            RankedTypes  = rankedTypes;
            RuleId       = ruleId;

            // All RankedTypes have been identified. Now explore method parameters
            // to deduce actual rules, and generate any 'list' (star, actually) rules
            // on-the-fly.

            var listRules    = new List <Rule>();
            var nextListRule = uncompiledRules.Count + TokenNames.Count;
            var rules        = uncompiledRules.Select(r => Compile(r, ref nextListRule, listRules)).ToArray();

            Rules = rules.Concat(listRules).ToArray();

            // The starting tokens for each rule

            var isStartOf = Enumerable.Range(TokenNames.Count, Rules.Count).Select(i =>
                                                                                   Rules.Select((r, j) => r.StartsWithRule(i) ? j : -1)
                                                                                   .Where(j => j >= 0).ToArray()).ToArray();

            Action <int, int> propagateStart = null;

            propagateStart = (stok, rul) =>
            {
                foreach (var rul2 in isStartOf[rul])
                {
                    if (!Rules[rul2].StartingTokens.Contains(stok))
                    {
                        Rules[rul2].StartingTokens.Add(stok);
                        propagateStart(stok, rul2);
                    }
                }
            };

            for (var r = 0; r < Rules.Count; ++r)
            {
                foreach (var tok in Rules[r].StartingTokens)
                {
                    propagateStart(tok, r);
                }
            }

            // The reducing tokens for each rule

            foreach (var r in Rules)
            {
                r.AddReducingToken(this, EndOfStream);
                r.ExtractEndingTokens(this);
            }
            // Initial rules

            int resultMaxRank;

            if (!MaxRank.TryGetValue(result, out resultMaxRank))
            {
                throw new Exception($"Unknown result type {result}.");
            }

            InitialRules = Enumerable.Range(0, resultMaxRank + 1).SelectMany(i =>
            {
                int id;
                return(RankedTypeId.TryGetValue(new RankedType(result, i), out id) ? RuleId[id] : new int[0]);
            }).ToArray();
        }