private Rule Select(DiscriminatorInfo discriminator) { ++this.discriminatorIndex; // eats the current token var nextToken = this.DiscriminatorPeek(); if (discriminator.SimpleDiscriminations.ContainsKey(nextToken)) { return(discriminator.SimpleDiscriminations[nextToken]); } if (discriminator.ComplexDiscriminations.ContainsKey(nextToken)) { var nestedDiscriminationInfo = discriminator.ComplexDiscriminations[nextToken]; return(nestedDiscriminationInfo.Item1[this.Select(nestedDiscriminationInfo.Item2)]); } throw new InvalidOperationException($"Expected one of the following tokens ({string.Join(", ", discriminator.SimpleDiscriminations.Keys.Concat(discriminator.ComplexDiscriminations.Keys))}), but found {nextToken}"); }
private DiscriminatorInfo GetDiscriminator(Token token, IReadOnlyList <Rule> rules, string name) { var prefixDiscriminator = this.discriminatorUsages.FirstOrDefault( u => u.Token == token && rules.All(r => u.Rules.Any(ur => r.Symbols.Take(ur.Symbols.Count).SequenceEqual(ur.Symbols))) ); if (prefixDiscriminator != null) { return(prefixDiscriminator.Discriminator); } var discriminators = rules.Select(r => new { r, remainings = this.GetRemainings(r, token) }) .ToArray(); var cacheKey = new DiscriminatorInfoCacheKey(discriminators.Select(t => t.remainings)); DiscriminatorInfo existing; if (this.discriminatorCache.TryGetValue(cacheKey, out existing)) { this.discriminatorUsages.Add(new DiscriminatorUsage { Discriminator = existing, Token = token, Rules = rules }); return(existing); } var discriminatorSymbol = new NonTerminal(name); var result = new DiscriminatorInfo { Symbol = discriminatorSymbol }; this.discriminatorCache.Add(cacheKey, result); this.discriminatorUsages.Add(new DiscriminatorUsage { Discriminator = result, Token = token, Rules = rules }); var discriminatorRules = discriminators.SelectMany(t => t.remainings, (t, remaining) => new { origRule = t.r, newRule = new Rule(discriminatorSymbol, remaining) }) .Select(t => new { t.origRule, t.newRule, next = this.NextOf(new Rule(t.origRule.Produced, t.newRule.Symbols)) }) .ToArray(); var allNexts = discriminatorRules.SelectMany(t => t.next).Distinct().ToArray(); var subDiscriminatorId = 0; foreach (var next in allNexts) { var matchingRules = discriminatorRules.Where(t => t.next.Contains(next)).ToArray(); if (matchingRules.Length == 1) { result.SimpleDiscriminations.Add(next, matchingRules.Single().origRule); } else { //var prefixDiscriminator = this.discriminatorUsages.FirstOrDefault( // u => u.Token == next // && matchingRules.All(r => u.Rules.Any(ur => r.newRule.Symbols.Take(ur.Symbols.Count).SequenceEqual(ur.Symbols))) //); //if (prefixDiscriminator != null) //{ // result.ComplexDiscriminations.Add( // next, // Tuple.Create( // matchingRules.ToDictionary(t => t.newRule, t => t.origRule), // wrong // prefixDiscriminator.Discriminator // ) // ); // continue; //} var subDiscriminator = this.GetDiscriminator( next, matchingRules.Select(t => t.newRule).ToArray(), name: $"{name}/{subDiscriminatorId++}" ); result.ComplexDiscriminations.Add( next, Tuple.Create( matchingRules.ToDictionary(t => t.newRule, t => t.origRule), subDiscriminator ) ); } } return(result); }