public void WriteParseCode(TextWriter writer, ScriptParserGenerator generator)
        {
            writer.Write(ScriptParserGenerator.GetAccessibilityString(generator.Settings.ParseMethodAccessibility));
            writer.Write(" ");
            writer.Write(generator.GetReturnClassIdentifier(this.DefinitionName));
            writer.Write(" ");
            writer.Write(generator.GetParseMethodIdentifier(this.DefinitionName));
            writer.WriteLine("() {");
            generator.IndentCount = 1;
            generator.InitializeVariableIndex(1);
            IDictionary <ElementsElement, MethodSignature> methods = this.GetReturnParameterSignaturesAndElements(generator);

            if (false)
            {
                // 普通のコード
                if (this.Expression.Selection.Candidates.Count >= 2)
                {
                    IList <string> firsts = this.Expression.Selection.GetFirstTerminals(generator);
                    string         peekVar;
                    writer.WriteLine(generator.GetCodeOfPeekOrThrow(this.DefinitionName, firsts, out peekVar));
                    Dictionary <string, string> usedFirsts = new Dictionary <string, string>();
                    foreach (ElementsElement elems in this.Expression.Selection.Candidates)
                    {
                        IList <string> innerFirsts = elems.GetFirstTerminals(generator);
                        foreach (string first in innerFirsts)
                        {
                            string usingPoint;
                            if (usedFirsts.TryGetValue(first, out usingPoint))
                            {
                                string context = string.Format("'{0}' の定義", this.DefinitionName);
                                string message = string.Format("<{1}> 内の <{0}> は <{2}> によって隠されます", first, elems.ToString(), usingPoint);
                                generator.Warn(context, message);
                            }
                            else
                            {
                                usedFirsts[first] = elems.ToString();
                            }
                        }
                        writer.WriteLine(generator.GetCodeOfIfLexisIn(peekVar, innerFirsts));

                        List <string> arguments = new List <string>();
                        foreach (ElementElement elem in elems.Elements)
                        {
                            string var = elem.WriteParseCode(writer, generator);
                            arguments.Add(var);
                        }
                        writer.WriteLine(generator.GetCodeOfReturnMethod(methods[elems].MethodName, arguments));
                        writer.Write(generator.GetCodeOfCloseBlock());
                        writer.Write(generator.GetCodeOfSingleElse());
                    }
                    writer.WriteLine(generator.GetCodeOfOpenBlock());

                    writer.WriteLine(generator.GetCodeOfThrowNew("System.NotImplementedException", ScriptParserGenerator.EscapeString(this.DefinitionName)));
                    writer.WriteLine(generator.GetCodeOfCloseBlock());
                }
                else
                {
                    ElementsElement elems       = this.Expression.Selection.Candidates.First();
                    IList <string>  innerFirsts = elems.GetFirstTerminals(generator);

                    List <string> arguments = new List <string>();
                    foreach (ElementElement elem in elems.Elements)
                    {
                        string var = elem.WriteParseCode(writer, generator);
                        arguments.Add(var);
                    }
                    writer.WriteLine(generator.GetCodeOfReturnMethod(methods[elems].MethodName, arguments));
                }
            }
            else
            {
                // 前半部分が同じSelectionをツリー状に探索するようにするために
                // SelectionSubCandidateを作る
                List <SelectionSubCandidate> subCandidates = new List <SelectionSubCandidate>();
                foreach (ElementsElement candidate in this.Expression.Selection.Candidates)
                {
                    subCandidates.Add(new SelectionSubCandidate(candidate));
                }

                SelectionSubCandidate.writeParseCodeAux(writer, generator, subCandidates, (candidateAtEmpty, writer2, generator2) => {
                    writer.WriteLine(generator.GetCodeOfReturnMethod(methods[candidateAtEmpty.OriginalElements].MethodName, candidateAtEmpty.TemporaryVariables));
                });
            }
            writer.Write("}");
        }
        public override string WriteParseCode(TextWriter writer, ScriptParserGenerator generator)
        {
            if (false)
            {
                // 普通のコード
                Debug.Assert(_candidates.Count >= 1);
                if (_candidates.Count == 1)
                {
                    return(_candidates.First().WriteParseCode(writer, generator));
                }
                else
                {
                    IList <string> firsts = this.GetFirstTerminals(generator);
                    string         peekVar;
                    writer.WriteLine(generator.GetCodeOfPeekOrThrow(this.RootDefinition.DefinitionName, firsts, out peekVar));
                    bool oneClassType;
                    ParameterSignature returnParam = GetReturnParameterSignature(generator, out oneClassType);
                    string             returnType  = returnParam.GetTypeName();
                    string             returnVar;
                    writer.WriteLine(generator.GetCodeOfDeclareDefault(returnType, out returnVar));
                    Dictionary <string, string> usedFirsts = new Dictionary <string, string>();
                    foreach (ElementsElement elems in _candidates)
                    {
                        IList <string> innerFirsts = elems.GetFirstTerminals(generator);
                        foreach (string first in innerFirsts)
                        {
                            string usingPoint;
                            if (usedFirsts.TryGetValue(first, out usingPoint))
                            {
                                string context = string.Format("'{0}' の定義", this.RootDefinition.DefinitionName);
                                string message = string.Format("<{1}> 内の <{0}> は <{2}> によって隠されます", first, this.ToString(), usingPoint);
                                generator.Warn(context, message);
                            }
                            else
                            {
                                usedFirsts[first] = elems.ToString();
                            }
                        }
                        writer.WriteLine(generator.GetCodeOfIfLexisIn(peekVar, innerFirsts));
                        string candidateVar = elems.WriteParseCode(writer, generator);
                        if (oneClassType)
                        {
                            writer.WriteLine(generator.GetCodeOfSubstitution(returnVar, candidateVar));
                        }
                        else
                        {
                            string selectVar;
                            writer.WriteLine(generator.GetCodeOfDeclareNew(returnType, new[] { candidateVar }, out selectVar));

                            writer.WriteLine(generator.GetCodeOfSubstitution(returnVar, selectVar));
                        }
                        writer.Write(generator.GetCodeOfCloseBlock());
                        writer.Write(generator.GetCodeOfSingleElse());
                    }
                    writer.Write(generator.GetCodeOfOpenBlock());
                    writer.WriteLine(generator.GetCodeOfCloseBlock());
                    return(returnVar);
                }
            }
            else
            {
                // 前半部分が同じSelectionをツリー状に探索するようにするために
                // SelectionSubCandidateを作る
                List <SelectionSubCandidate> subCandidates = new List <SelectionSubCandidate>();
                foreach (ElementsElement candidate in _candidates)
                {
                    subCandidates.Add(new SelectionSubCandidate(candidate));
                }
                bool oneClassType;
                ParameterSignature returnParam = this.GetReturnParameterSignature(generator, out oneClassType);
                string             returnVariableName;
                writer.WriteLine(generator.GetCodeOfDeclareDefault(returnParam.GetTypeName(), out returnVariableName));

                SelectionSubCandidate.writeParseCodeAux(writer, generator, subCandidates, (candidateAtEmpty, writer2, generator2) => {
                    // 候補の要素が単一要素の場合はFixedListをnewしなくてよいので分ける
                    string resultVar;
                    if (candidateAtEmpty.OriginalElements.Elements.Count == 1)
                    {
                        resultVar = candidateAtEmpty.TemporaryVariables.First();
                    }
                    else
                    {
                        ParameterSignature returnParam2 = candidateAtEmpty.OriginalElements.GetReturnParameterSignature(generator2);
                        string typename = returnParam2.GetTypeName();
                        writer2.WriteLine(generator2.GetCodeOfDeclareNew(typename, candidateAtEmpty.TemporaryVariables, out resultVar));
                    }
                    bool oneClassReturn;
                    ParameterSignature tmpReturnParam = this.GetReturnParameterSignature(generator2, out oneClassReturn);
                    if (!oneClassReturn)
                    {
                        // 一回Selection<>を作成しないといけない
                        string tmpTypename = tmpReturnParam.GetTypeName();
                        string tmpResultVar;
                        writer.WriteLine(generator2.GetCodeOfDeclareNew(tmpTypename, new[] { resultVar }, out tmpResultVar));
                        resultVar = tmpResultVar;
                    }
                    writer2.WriteLine(generator.GetCodeOfSubstitution(returnVariableName, resultVar));
                });
                return(returnVariableName);
            }
        }
        public static void writeParseCodeAux(TextWriter writer, ScriptParserGenerator generator, IList <SelectionSubCandidate> subCandidates, Action <SelectionSubCandidate, TextWriter, ScriptParserGenerator> returnCodeGenerate)
        {
            Debug.Assert(subCandidates.Count >= 1);
            DefinitionElement rootDefinition = subCandidates.First().RootElement;

            // 先頭のDefinitionContentが同じである選択候補の集合
            Dictionary <DefinitionContent, List <SelectionSubCandidate> > sameHeadCandidates = new Dictionary <DefinitionContent, List <SelectionSubCandidate> >(new DefinitionContentComparer());
            // 優先順位を保つために順番を覚えておく
            List <DefinitionContent> headOrder = new List <DefinitionContent>();
            // 後続の要素がない選択候補の集合
            List <SelectionSubCandidate> noElementCandidates = new List <SelectionSubCandidate>();

            // 選択候補を先頭の要素ごとに振り分け
            foreach (SelectionSubCandidate sub in subCandidates)
            {
                List <SelectionSubCandidate> list;
                if (sub.IsEmpty)
                {
                    noElementCandidates.Add(sub);
                }
                else
                {
                    if (!sameHeadCandidates.TryGetValue(sub.Head, out list))
                    {
                        sameHeadCandidates[sub.Head] = list = new List <SelectionSubCandidate>();
                        headOrder.Add(sub.Head);
                    }
                    list.Add(sub);
                }
            }
            Dictionary <string, string> usedFirsts = new Dictionary <string, string>();
            Dictionary <DefinitionContent, string[]> firstTerminals = new Dictionary <DefinitionContent, string[]>();

            foreach (DefinitionContent head in headOrder)
            {
                // 先頭が同じ候補の集合
                List <SelectionSubCandidate> list;
                bool getListFromHeadSucceeded = sameHeadCandidates.TryGetValue(head, out list);
                Debug.Assert(getListFromHeadSucceeded);
                // 現在の先頭要素の中での頭にくる可能性のある終端記号
                HashSet <string> firstsAtThisHead = new HashSet <string>();
                foreach (SelectionSubCandidate sub in list)
                {
                    IList <string> firsts = sub.GetFirstTerminals(generator);
                    foreach (string first in firsts)
                    {
                        // もう追加した場合はスルー
                        if (firstsAtThisHead.Contains(first))
                        {
                            continue;
                        }
                        firstsAtThisHead.Add(first);
                        // 他の先頭のときに使っている終端記号が頭にくる可能性がある場合は警告
                        string usingPoint;
                        if (usedFirsts.TryGetValue(first, out usingPoint))
                        {
                            string context = string.Format("'{0}' の定義", rootDefinition.DefinitionName);
                            string message = string.Format("<{1}> 内の <{0}> は <{2}> によって隠されます", first, sub.OriginalElements.ToString(), usingPoint);
                            generator.Warn(context, message);
                        }
                        else
                        {
                            usedFirsts[first] = sub.OriginalElements.ToString();
                        }
                    }
                }
                firstTerminals[head] = firstsAtThisHead.ToArray();
            }
            bool isSingleCandidate = sameHeadCandidates.Count == 1 && noElementCandidates.Count == 0;

            if (isSingleCandidate)
            {
                List <SelectionSubCandidate> list             = sameHeadCandidates.Values.First();
                string[]                     firstsAtThisHead = firstTerminals.Values.First();
                DefinitionContent            head             = list.First().Head;
                string                       headVar          = head.WriteParseCode(writer, generator);
                List <SelectionSubCandidate> next             = new List <SelectionSubCandidate>();
                foreach (SelectionSubCandidate sub in list)
                {
                    next.Add(sub.NextElement(headVar));
                }
                writeParseCodeAux(writer, generator, next, returnCodeGenerate);
                return;
            }
            bool needsBlockAtEmpty = headOrder.Count >= 1;
            bool usePeekOrThrow    = noElementCandidates.Count == 0;

            // 後続の要素があるものは再帰的に処理
            if (headOrder.Count >= 1)
            {
                string peek;
                if (usePeekOrThrow)
                {
                    IList <string> validTerminals = firstTerminals.Values.SelectMany(terminals => terminals).Distinct().ToList();
                    writer.WriteLine(generator.GetCodeOfPeekOrThrow(rootDefinition.DefinitionName, validTerminals, out peek));
                }
                else
                {
                    // 後続の要素がない場合もあるのでPeekOrThrowではなくPeek
                    writer.WriteLine(generator.GetCodeOfPeek(out peek));
                }
                // 順番通りに
                foreach (DefinitionContent head in headOrder)
                {
                    // 先頭が同じ候補の集合
                    List <SelectionSubCandidate> list;
                    bool getListFromHeadSucceeded = sameHeadCandidates.TryGetValue(head, out list);
                    Debug.Assert(getListFromHeadSucceeded);
                    // 現在の先頭要素の中での頭にくる可能性のある終端記号
                    string[] firstsAtThisHead;
                    bool     getFirstsFromHeadSucceeded = firstTerminals.TryGetValue(head, out firstsAtThisHead);
                    Debug.Assert(getFirstsFromHeadSucceeded);
                    // 頭の終端記号が対象のであるか
                    if (usePeekOrThrow)
                    {
                        writer.WriteLine(generator.GetCodeOfIfLexisIn(peek, firstsAtThisHead));
                    }
                    else
                    {
                        writer.WriteLine(generator.GetCodeOfIfOptionalLexisIn(peek, firstsAtThisHead));
                    }
                    // 先頭の要素をパース
                    string headVar = head.WriteParseCode(writer, generator);
                    // 後続を再帰的に処理
                    List <SelectionSubCandidate> next = new List <SelectionSubCandidate>();
                    foreach (SelectionSubCandidate sub in list)
                    {
                        next.Add(sub.NextElement(headVar));
                    }
                    writeParseCodeAux(writer, generator, next, returnCodeGenerate);
                    writer.Write(generator.GetCodeOfCloseBlock());
                    writer.Write(generator.GetCodeOfSingleElse());
                }
            }
            // 同じ内容なのが二つあった時は警告を出す
            if (noElementCandidates.Count >= 2)
            {
                SelectionSubCandidate oneOfCandidate = noElementCandidates.First();
                foreach (SelectionSubCandidate emptyElse in noElementCandidates.Skip(1))
                {
                    string context = string.Format("'{0}' の定義", rootDefinition.DefinitionName);
                    string message = string.Format("<{0}> は <{1}> によって隠されます", emptyElse.OriginalElements.ToString(), oneOfCandidate.OriginalElements.ToString());
                    generator.Warn(context, message);
                }
            }
            if (needsBlockAtEmpty)
            {
                writer.WriteLine(generator.GetCodeOfOpenBlock());
            }
            if (noElementCandidates.Count >= 1)
            {
                SelectionSubCandidate elements = noElementCandidates.First();
                returnCodeGenerate(elements, writer, generator);
            }
            else
            {
                IList <string> availableTerminals = new List <string>(usedFirsts.Keys);
                writer.WriteLine(generator.GetCodeOfThrowError(rootDefinition.DefinitionName, availableTerminals));
            }
            if (needsBlockAtEmpty)
            {
                writer.WriteLine(generator.GetCodeOfCloseBlock());
            }
        }