PageRenderTime 45ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

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