PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 17ms RepoModel.GetById 3ms app.codeStats 0ms

/XObjects/Src/FSMGenerator.cs

https://bitbucket.org/hma2/sdmxsource.net
C# | 384 lines | 305 code | 62 blank | 17 comment | 48 complexity | b6550d94ffdfa4cfcfb9fb4ce9eee5b4 MD5 | raw file
  1//Copyright (c) Microsoft Corporation.  All rights reserved.
  2
  3using System;
  4using System.Collections;
  5using System.Collections.Generic;
  6using System.Xml;
  7using System.Xml.Schema;
  8using System.Xml.Linq;
  9using System.IO;
 10using System.Linq;
 11using System.Threading;
 12using System.Diagnostics;
 13using System.Reflection;
 14using Xml.Schema.Linq;
 15using System.Text;
 16using System.CodeDom;
 17
 18namespace Xml.Schema.Linq.CodeGen {
 19    internal abstract partial class ContentInfo {//Code for generating FSM
 20        internal virtual FSM MakeFSM(StateNameSource stateNames) {
 21            throw new InvalidOperationException();
 22        }
 23        
 24        internal FSM ImplementFSMCardinality(FSM origFsm, StateNameSource stateNames) {
 25            //Based on the occurence, add *,+, or ? semantics
 26            Debug.Assert(origFsm != null);
 27            FSM fsm = null;
 28            switch (this.OccursInSchema) {
 29                case Occurs.OneOrMore:
 30                    fsm = MakePlusFSM(origFsm, stateNames); break;
 31                case Occurs.ZeroOrMore:
 32                    fsm = MakeStarFSM(origFsm, stateNames); break;
 33                case Occurs.ZeroOrOne:
 34                    fsm = MakeQMarkFSM(origFsm, stateNames); break;
 35                default:
 36                    fsm = origFsm;
 37                    break;
 38            }
 39            
 40            return fsm;
 41        }
 42        
 43        private FSM MakePlusFSM(FSM origFsm, StateNameSource stateNames) {
 44            //Clone transitions in the initial state into each final state
 45            int origStart = origFsm.Start;
 46            foreach(int s in origFsm.Accept) {
 47                if (s != origStart) FSM.CloneTransitions(origFsm, origStart, origFsm, s);                
 48            }
 49            
 50            return origFsm;
 51        }
 52        
 53        private FSM MakeStarFSM(FSM origFsm, StateNameSource stateNames) {
 54            int start = origFsm.Start;
 55            Set<int> visited = new Set<int>();
 56            TransformToStar(start, start, origFsm, visited);
 57            origFsm.Accept.Add(start);
 58
 59            return origFsm;
 60        }
 61
 62        private void TransformToStar<T>(
 63            Dictionary<T, int> transitions,
 64            int startState,
 65            int currentState,
 66            FSM fsm,
 67            Set<int> visited)
 68        {
 69            if (transitions != null)
 70            {
 71                var toReroute = new List<T>();
 72                foreach (var transition in transitions)
 73                {
 74                    int nextState = transition.Value;
 75                    bool hasNextStates =
 76                        currentState != nextState &&
 77                        this.HasNextStates(nextState, fsm);
 78                    if (fsm.isAccept(nextState))
 79                    {
 80                        if (hasNextStates)
 81                        {
 82                            // see http://linqtoxsd.codeplex.com/WorkItem/View.aspx?WorkItemId=4083
 83                            if (!visited.Contains(nextState))
 84                            {
 85                                this.SimulatePlusQMark(fsm, startState, nextState);
 86                            }
 87                        }
 88                        else
 89                        {
 90                            toReroute.Add(transition.Key);
 91                        }
 92                    }
 93                    if (hasNextStates)
 94                    {
 95                        this.TransformToStar(startState, nextState, fsm, visited);
 96                    }
 97                }
 98                foreach (var id in toReroute)
 99                {
100                    transitions[id] = startState;
101                }
102            }
103        }
104
105        private void TransformToStar(int start, int currState, FSM fsm, Set<int> visited)
106        {
107            if (visited.Contains(currState)) return;
108            else visited.Add(currState);
109
110            Transitions currTrans = null;
111            fsm.Trans.TryGetValue(currState, out currTrans);
112            if (currTrans == null || currTrans.Count == 0) return;
113
114            this.TransformToStar(
115                currTrans.nameTransitions, start, currState, fsm, visited);
116            this.TransformToStar(
117                currTrans.wildCardTransitions, start, currState, fsm, visited);
118        }
119
120        private void SimulatePlusQMark(FSM fsm, int start, int currState) {
121            //Simulate * using Plus and QMark
122            if (currState != start) {
123                FSM.CloneTransitions(fsm, start, fsm, currState);                
124            }
125        }
126        
127        private bool HasNextStates(int state, FSM fsm) {
128            Transitions currTrans = null;
129            fsm.Trans.TryGetValue(state, out currTrans);
130            if (currTrans == null || currTrans.Count == 0) return false;
131            return true;
132
133        }
134
135        private FSM MakeQMarkFSM(FSM origFsm, StateNameSource stateNames) {
136             //Change the start state to the final states
137            origFsm.Accept.Add(origFsm.Start);
138            return origFsm;
139        }
140    }
141    
142    internal partial class GroupingInfo {
143        internal override FSM MakeFSM(StateNameSource stateNames) {
144            FSM fsm = null;
145            switch(this.contentModelType) {
146                case ContentModelType.Sequence: 
147                    fsm = MakeSequenceFSM(stateNames); break;
148                case ContentModelType.Choice: 
149                    fsm = MakeChoiceFSM(stateNames); break;
150                default: 
151                    throw new InvalidOperationException();
152            }
153            
154            return ImplementFSMCardinality(fsm, stateNames);                      
155        }
156        
157        private FSM MakeSequenceFSM(StateNameSource stateNames) {
158            FSM fsm = null;
159            Set<int> fsmAccept = null;
160            
161            foreach(ContentInfo child in Children) {
162                FSM currFsm = child.MakeFSM(stateNames);
163                
164                if (fsm == null) {
165                    fsm = currFsm;
166                    fsmAccept = currFsm.Accept;
167                }
168                else {
169                    int currStart = currFsm.Start;
170                    foreach(int oldFinalState in fsmAccept) {
171                       FSM.CloneTransitions(currFsm, currStart, fsm, oldFinalState);
172                     }
173                    fsm.AddTransitions(currFsm);
174                    //clear old final states only if the initial state of currFsm is not a final state in currFsm
175                    if (!currFsm.Accept.Contains(currStart)) fsmAccept.Clear();
176                    Set<int> currAccept = currFsm.Accept;
177                    foreach(int state in currAccept) fsmAccept.Add(state);
178                    
179                }
180
181            }
182            return fsm;
183        }
184
185        private FSM MakeChoiceFSM(StateNameSource stateNames) {
186            FSM fsm = null;
187            int fsmStart = FSM.InvalidState;
188            Set<int> fsmAccept = null;
189            
190            foreach (ContentInfo child in Children) {
191                FSM currFsm = child.MakeFSM(stateNames);
192                
193                if (fsm == null) {//first node
194                    fsm = currFsm;
195                    fsmStart = currFsm.Start;
196                    fsmAccept = currFsm.Accept;
197                }
198                else {
199                    //Merge the start states
200                    FSM.CloneTransitions(currFsm, currFsm.Start, fsm, fsmStart);
201                    //Copy other transitions
202                    fsm.AddTransitions(currFsm);
203                    //update final states
204                    if (currFsm.isAccept(currFsm.Start)) fsmAccept.Add(fsmStart);
205                    foreach(int state in currFsm.Accept) fsmAccept.Add(state);
206                }
207            }
208
209            return fsm;
210        }
211
212    }
213    
214    internal partial class ClrPropertyInfo : ClrBasePropertyInfo {
215        internal override FSM MakeFSM(StateNameSource stateNames) {
216            //Create a simple fsm with (0,(schemaName,1),{1})
217            Dictionary<int, Transitions> transitions = new Dictionary<int,Transitions>();
218            int start = stateNames.Next();
219            int end = stateNames.Next();
220            Transitions trans = new Transitions();
221
222            if (this.IsSubstitutionHead) {
223                foreach(XmlSchemaElement element in SubstitutionMembers) {
224                    trans.Add(XName.Get(element.QualifiedName.Name, element.QualifiedName.Namespace), end);
225                }
226            }
227            else {
228                trans.Add(XName.Get(schemaName, PropertyNs), end);
229            }
230                      
231            transitions.Add(start, trans);
232            return ImplementFSMCardinality(new FSM(start, new Set<int>(end), transitions), stateNames);
233        }
234    }
235
236    internal partial class ClrWildCardPropertyInfo : ClrBasePropertyInfo {
237        internal override FSM MakeFSM(StateNameSource stateNames) {
238            Dictionary<int, Transitions> transitions = new Dictionary<int,Transitions>();
239            int start = stateNames.Next();
240            int end = stateNames.Next();
241            transitions.Add(start, new Transitions(new SingleTransition(new WildCard(this.Namespaces, this.TargetNamespace), end)));
242            FSM fsm = new FSM(start, new Set<int>(end), transitions);
243            
244            return ImplementFSMCardinality(fsm, stateNames);
245        }
246    }
247
248    internal class StateNameSource {
249        private int nextName = 1;
250
251        internal int Next() { 
252            return nextName++; 
253        }
254
255        internal void Reset() {
256            nextName = 1;
257        }
258   }
259
260    internal class FSMCodeDomHelper{
261        internal static void CreateFSMStmt(FSM fsm, CodeStatementCollection stmts) {
262            //First create: Dictionary<int, Transitions> transitions = new Dictionary<int,Transitions>();
263            //Then create: transitions.Add(0, new Transitions(...));
264            //Last: fsm = new DFA(start, new Set<int>(end), transitions);
265            CodeTypeReference typeRef = CodeDomHelper.CreateGenericTypeReference("Dictionary", new string[]{Constants.Int, "Transitions"});
266            stmts.Add(new CodeVariableDeclarationStatement(typeRef, Constants.TransitionsVar, new CodeObjectCreateExpression(typeRef, new CodeExpression[] { })));
267            
268            //Then add all transitions
269            Set<int> visited = new Set<int>();
270            AddTransitions(fsm, fsm.Start, stmts, visited);
271
272            //Clean up accept states
273            Set<int> reachableAccept = new Set<int>();
274            foreach(int state in fsm.Accept) {
275                if (visited.Contains(state)) reachableAccept.Add(state);
276            }
277            
278            stmts.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(Constants.FSMMember),
279                             new CodeObjectCreateExpression(new CodeTypeReference(Constants.FSMClass),
280                                new CodePrimitiveExpression(fsm.Start),
281                                CreateSetCreateExpression(reachableAccept),
282                                new CodeVariableReferenceExpression(Constants.TransitionsVar))));
283
284
285        }
286
287        internal static void AddTransitions(FSM fsm, int state, CodeStatementCollection stmts, Set<int> visited) {
288            if (visited.Contains(state)) return;
289                else visited.Add(state);
290
291            Transitions currTrans = null;
292            fsm.Trans.TryGetValue(state, out currTrans);
293            if (currTrans == null || currTrans.Count == 0) return;
294
295            CreateAddTransitionStmts(fsm, stmts, state, currTrans, visited);
296            
297        }
298
299        internal static void CreateAddTransitionStmts(FSM fsm,
300                                               CodeStatementCollection stmts,
301                                               int state,
302                                               Transitions currTrans,
303                                               Set<int> visited) {
304           Set<int> subStates = new Set<int>();
305           CodeExpression[] initializers = new CodeExpression[currTrans.Count];
306           
307           int index = 0;
308           if (currTrans.nameTransitions != null)
309               foreach (KeyValuePair<XName, int> s1Trans in currTrans.nameTransitions) {
310                   initializers[index++] = CreateSingleTransitionExpr(CreateXNameExpr(s1Trans.Key), s1Trans.Value);
311                   subStates.Add(s1Trans.Value);
312
313               }
314
315           if (currTrans.wildCardTransitions != null)
316               foreach (KeyValuePair<WildCard, int> s1Trans in currTrans.wildCardTransitions) {
317                   initializers[index++] = CreateSingleTransitionExpr(CreateWildCardExpr(s1Trans.Key), s1Trans.Value);
318                   subStates.Add(s1Trans.Value);
319               }
320
321           
322           stmts.Add(CodeDomHelper.CreateMethodCall(new CodeVariableReferenceExpression(Constants.TransitionsVar),
323                                               "Add",
324                                               new CodeExpression[]{
325                                                   new CodePrimitiveExpression(state),
326                                                   new CodeObjectCreateExpression("Transitions", initializers)}));
327
328            //Recursively call AddTransitions on subsequent states
329           foreach(int s in subStates)  AddTransitions(fsm, s, stmts, visited);
330        }
331
332        
333        internal static CodeExpression CreateSingleTransitionExpr(CodeExpression labelExpr, int nextState) {
334            return new CodeObjectCreateExpression(
335                   Constants.SingleTrans,
336                   labelExpr,
337                   new CodePrimitiveExpression(nextState));
338        }
339
340        internal static CodeExpression CreateXNameExpr(XName name) {
341            return CodeDomHelper.CreateMethodCall(new CodeTypeReferenceExpression("XName"),
342                                                  "Get",
343                                                  new CodeExpression[]{
344                                                      new CodePrimitiveExpression(name.LocalName),
345                                                      new CodePrimitiveExpression(name.Namespace.NamespaceName)
346                                                  });
347        }
348
349        internal static CodeExpression CreateWildCardExpr(WildCard any) {
350            return new CodeObjectCreateExpression(
351                Constants.WildCard,
352                new CodeExpression[]{
353                    new CodePrimitiveExpression(any.NsList.Namespaces),
354                    new CodePrimitiveExpression(any.NsList.TargetNamespace)
355                }
356                );
357        }
358
359        internal static CodeObjectCreateExpression CreateSetCreateExpression(Set<int> set) {
360            CodeObjectCreateExpression createSet = 
361                new CodeObjectCreateExpression(CodeDomHelper.CreateGenericTypeReference("Set", new string[]{Constants.Int}));
362            
363            CodeExpressionCollection parameters = createSet.Parameters;    
364            if (set.Count == 1) {
365                foreach(int i in set) {
366                    parameters.Add(new CodePrimitiveExpression(i));
367                }
368            }
369            else if (set.Count > 1) {
370                CodeArrayCreateExpression array = new CodeArrayCreateExpression();
371                array.CreateType = CodeDomHelper.CreateTypeReference(Constants.Int);
372                    
373                CodeExpressionCollection initializers = array.Initializers;
374                foreach(int i in set) {
375                    initializers.Add(new CodePrimitiveExpression(i));
376                }
377                parameters.Add(array);
378            }
379
380            return createSet;
381        }
382    }
383
384}