PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/ModelViewer/DafnyProvider.cs

http://boogie.codeplex.com
C# | 385 lines | 328 code | 41 blank | 16 comment | 65 complexity | 83029574bd4faf3bdd13affc04273d7e MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Diagnostics.Contracts;
  7. namespace Microsoft.Boogie.ModelViewer.Dafny
  8. {
  9. public class Provider : ILanguageProvider
  10. {
  11. public static Provider Instance = new Provider();
  12. private Provider() { }
  13. public bool IsMyModel(Model m)
  14. {
  15. return m.TryGetFunc("$$Language$Dafny") != null;
  16. }
  17. public ILanguageSpecificModel GetLanguageSpecificModel(Model m, ViewOptions opts)
  18. {
  19. var dm = new DafnyModel(m, opts);
  20. foreach (var s in m.States) {
  21. var sn = new StateNode(dm.states.Count, dm, s);
  22. dm.states.Add(sn);
  23. }
  24. dm.FinishStates();
  25. return dm;
  26. }
  27. }
  28. class DafnyModel : LanguageModel
  29. {
  30. public readonly Model.Func f_heap_select, f_set_select, f_seq_length, f_seq_index, f_box, f_dim, f_index_field, f_multi_index_field, f_dtype, f_null;
  31. public readonly Dictionary<Model.Element, Model.Element[]> ArrayLengths = new Dictionary<Model.Element, Model.Element[]>();
  32. public readonly Dictionary<Model.Element, Model.FuncTuple> DatatypeValues = new Dictionary<Model.Element, Model.FuncTuple>();
  33. Dictionary<Model.Element, string> typeName = new Dictionary<Model.Element, string>();
  34. public List<StateNode> states = new List<StateNode>();
  35. public DafnyModel(Model m, ViewOptions opts)
  36. : base(m, opts)
  37. {
  38. f_heap_select = m.MkFunc("[3]", 3);
  39. f_set_select = m.MkFunc("[2]", 2);
  40. f_seq_length = m.MkFunc("Seq#Length", 1);
  41. f_seq_index = m.MkFunc("Seq#Index", 2);
  42. f_box = m.MkFunc("$Box", 1);
  43. f_dim = m.MkFunc("FDim", 1);
  44. f_index_field = m.MkFunc("IndexField", 1);
  45. f_multi_index_field = m.MkFunc("MultiIndexField", 2);
  46. f_dtype = m.MkFunc("dtype", 1);
  47. f_null = m.MkFunc("null", 0);
  48. // collect the array dimensions from the various array.Length functions, and
  49. // collect all known datatype values
  50. foreach (var fn in m.Functions) {
  51. if (Regex.IsMatch(fn.Name, "^_System.array[0-9]*.Length[0-9]*$")) {
  52. int j = fn.Name.IndexOf('.', 13);
  53. int dims = j == 13 ? 1 : int.Parse(fn.Name.Substring(13, j - 13));
  54. int idx = j == 13 ? 0 : int.Parse(fn.Name.Substring(j + 7));
  55. foreach (var tpl in fn.Apps) {
  56. var elt = tpl.Args[0];
  57. var len = tpl.Result;
  58. Model.Element[] ar;
  59. if (!ArrayLengths.TryGetValue(elt, out ar)) {
  60. ar = new Model.Element[dims];
  61. ArrayLengths.Add(elt, ar);
  62. }
  63. Contract.Assert(ar[idx] == null);
  64. ar[idx] = len;
  65. }
  66. } else if (fn.Name.StartsWith("#") && fn.Name.IndexOf('.') != -1 && fn.Name[1] != '#') {
  67. foreach (var tpl in fn.Apps) {
  68. var elt = tpl.Result;
  69. DatatypeValues.Add(elt, tpl);
  70. }
  71. }
  72. }
  73. }
  74. internal void FinishStates()
  75. {
  76. GenerateSourceLocations(states);
  77. }
  78. public override IEnumerable<IState> States
  79. {
  80. get { return states; }
  81. }
  82. public string GetUserVariableName(string name)
  83. {
  84. if (name.StartsWith("$")) // this covers $Heap and $_Frame and $nw...
  85. return null;
  86. if (name.Contains("##")) // a temporary variable of the translation
  87. return null;
  88. #if SOMETIME_AGAIN
  89. var hash = name.IndexOf('#');
  90. if (0 < hash)
  91. return name.Substring(0, hash);
  92. #endif
  93. return name;
  94. }
  95. public Model.Element Image(Model.Element elt, Model.Func f)
  96. {
  97. var r = f.AppWithResult(elt);
  98. if (r != null)
  99. return r.Args[0];
  100. return null;
  101. }
  102. protected override string CanonicalBaseName(Model.Element elt, out NameSeqSuffix suff)
  103. {
  104. Model.FuncTuple fnTuple;
  105. suff = NameSeqSuffix.WhenNonZero;
  106. if (DatatypeValues.TryGetValue(elt, out fnTuple)) {
  107. // elt is s a datatype value, make its name be the name of the datatype constructor
  108. string nm = fnTuple.Func.Name;
  109. if (fnTuple.Func.Arity == 0)
  110. return nm;
  111. else
  112. return nm + "(...)";
  113. }
  114. var seqLen = f_seq_length.AppWithArg(0, elt);
  115. if (seqLen != null) {
  116. // elt is a sequence
  117. return string.Format("[Length {0}]", seqLen.Result.AsInt());
  118. }
  119. if (elt == f_null.GetConstant())
  120. return "null";
  121. var tp = f_dtype.TryEval(elt);
  122. if (tp != null) {
  123. foreach (var app in tp.References) {
  124. if (app.Args.Length == 0 && app.Func.Name.StartsWith("class.")) {
  125. suff = NameSeqSuffix.Always;
  126. return app.Func.Name.Substring(6);
  127. }
  128. }
  129. }
  130. return base.CanonicalBaseName(elt, out suff);
  131. }
  132. public IEnumerable<ElementNode> GetExpansion(StateNode state, Model.Element elt)
  133. {
  134. List<ElementNode> result = new List<ElementNode>();
  135. if (elt.Kind != Model.ElementKind.Uninterpreted)
  136. return result;
  137. // Perhaps elt is a known datatype value
  138. Model.FuncTuple fnTuple;
  139. if (DatatypeValues.TryGetValue(elt, out fnTuple)) {
  140. // elt is a datatype value
  141. int i = 0;
  142. foreach (var arg in fnTuple.Args) {
  143. var edgname = new EdgeName(this, i.ToString());
  144. result.Add(new FieldNode(state, edgname, arg));
  145. i++;
  146. }
  147. return result;
  148. }
  149. // Perhaps elt is a sequence
  150. var seqLen = f_seq_length.AppWithArg(0, elt);
  151. if (seqLen != null) {
  152. // elt is a sequence
  153. foreach (var tpl in f_seq_index.AppsWithArg(0, elt)) {
  154. var edgname = new EdgeName(this, "[%0]", tpl.Args[1]);
  155. result.Add(new FieldNode(state, edgname, Unbox(tpl.Result)));
  156. }
  157. return result;
  158. }
  159. // Perhaps elt is a set
  160. foreach (var tpl in f_set_select.AppsWithArg(0, elt)) {
  161. var setElement = tpl.Args[1];
  162. var containment = tpl.Result;
  163. var edgname = new EdgeName(this, "[%0]", Unbox(setElement));
  164. result.Add(new FieldNode(state, edgname, containment));
  165. }
  166. if (result.Count != 0)
  167. return result; // elt is a set
  168. // It seems elt is an object or array
  169. Model.Element[] lengths;
  170. if (ArrayLengths.TryGetValue(elt, out lengths)) {
  171. int i = 0;
  172. foreach (var len in lengths) {
  173. var name = lengths.Length == 1 ? "Length" : "Length" + i;
  174. var edgname = new EdgeName(this, name);
  175. result.Add(new FieldNode(state, edgname, len));
  176. i++;
  177. }
  178. }
  179. var heap = state.State.TryGet("$Heap");
  180. if (heap != null) {
  181. foreach (var tpl in f_heap_select.AppsWithArgs(0, heap, 1, elt)) {
  182. var field = new FieldName(tpl.Args[2], this);
  183. if (field.NameFormat != "alloc") {
  184. var edgname = new EdgeName(this, field.NameFormat, field.NameArgs);
  185. result.Add(new FieldNode(state, edgname, Unbox(tpl.Result)));
  186. }
  187. }
  188. }
  189. return result;
  190. }
  191. class FieldName
  192. {
  193. public readonly Model.Element Field;
  194. public readonly int Dims;
  195. public readonly string NameFormat;
  196. public readonly Model.Element[] NameArgs;
  197. public FieldName(Model.Element elt, DafnyModel dm) {
  198. Field = elt;
  199. var tpl = dm.f_dim.AppWithArg(0, elt);
  200. if (tpl != null) {
  201. Dims = tpl.Result.AsInt();
  202. NameArgs = new Model.Element[Dims];
  203. for (int i = Dims; 0 <= --i; ) {
  204. if (i == 0) {
  205. tpl = dm.f_index_field.AppWithResult(elt);
  206. NameArgs[i] = tpl.Args[0];
  207. } else {
  208. tpl = dm.f_multi_index_field.AppWithResult(elt);
  209. NameArgs[i] = tpl.Args[1];
  210. elt = tpl.Args[0];
  211. }
  212. }
  213. }
  214. // now for the name
  215. if (Dims == 0) {
  216. NameFormat = Field.ToString();
  217. foreach (var n in Field.Names) {
  218. NameFormat = n.Func.Name;
  219. int dot = NameFormat.LastIndexOf('.');
  220. if (0 <= dot)
  221. NameFormat = NameFormat.Substring(dot + 1);
  222. break;
  223. }
  224. } else {
  225. NameFormat = "[";
  226. string sep = "";
  227. for (int i = 0; i < Dims; i++) {
  228. NameFormat += sep + "%" + i;
  229. sep = ",";
  230. }
  231. NameFormat += "]";
  232. }
  233. }
  234. }
  235. Model.Element Unbox(Model.Element elt) {
  236. var unboxed = f_box.AppWithResult(elt);
  237. if (unboxed != null)
  238. return unboxed.Args[0];
  239. else
  240. return elt;
  241. }
  242. }
  243. class StateNode : NamedState
  244. {
  245. internal readonly DafnyModel dm;
  246. internal readonly List<VariableNode> vars = new List<VariableNode>();
  247. internal readonly List<VariableNode> skolems;
  248. internal readonly int index;
  249. public StateNode(int i, DafnyModel parent, Model.CapturedState s)
  250. : base(s, parent)
  251. {
  252. dm = parent;
  253. state = s;
  254. index = i;
  255. skolems = new List<VariableNode>(SkolemVars());
  256. SetupVars();
  257. }
  258. void SetupVars()
  259. {
  260. var names = Util.Empty<string>();
  261. if (dm.states.Count > 0) {
  262. var prev = dm.states.Last();
  263. names = prev.vars.Map(v => v.realName);
  264. }
  265. names = names.Concat(state.Variables).Distinct();
  266. var curVars = state.Variables.ToDictionary(x => x);
  267. foreach (var v in names) {
  268. if (dm.GetUserVariableName(v) != null) {
  269. var val = state.TryGet(v);
  270. var vn = new VariableNode(this, v, val);
  271. vn.updatedHere = dm.states.Count > 0 && curVars.ContainsKey(v);
  272. if (curVars.ContainsKey(v))
  273. dm.RegisterLocalValue(vn.Name, val);
  274. vars.Add(vn);
  275. }
  276. }
  277. dm.Flush(Nodes);
  278. }
  279. IEnumerable<VariableNode> SkolemVars() {
  280. foreach (var f in dm.model.Functions) {
  281. if (f.Arity != 0) continue;
  282. int n = f.Name.IndexOf('!');
  283. if (n == -1) continue;
  284. string name = f.Name.Substring(0, n);
  285. if (!name.Contains('#')) continue;
  286. yield return new VariableNode(this, name, f.GetConstant());
  287. }
  288. }
  289. public override IEnumerable<IDisplayNode> Nodes
  290. {
  291. get {
  292. return vars.Concat(skolems);
  293. }
  294. }
  295. }
  296. class ElementNode : DisplayNode
  297. {
  298. protected StateNode stateNode;
  299. protected Model.Element elt;
  300. protected DafnyModel vm { get { return stateNode.dm; } }
  301. public ElementNode(StateNode st, EdgeName name, Model.Element elt)
  302. : base(st.dm, name, elt)
  303. {
  304. this.stateNode = st;
  305. this.elt = elt;
  306. }
  307. public ElementNode(StateNode st, string name, Model.Element elt)
  308. : this(st, new EdgeName(name), elt) { }
  309. protected override void ComputeChildren()
  310. {
  311. children.AddRange(vm.GetExpansion(stateNode, elt));
  312. }
  313. }
  314. class FieldNode : ElementNode
  315. {
  316. public FieldNode(StateNode par, EdgeName realName, Model.Element elt)
  317. : base(par, realName, elt)
  318. {
  319. /*
  320. var idx = realName.LastIndexOf('.');
  321. if (idx > 0)
  322. name = realName.Substring(idx + 1);
  323. */
  324. }
  325. }
  326. class MapletNode : ElementNode
  327. {
  328. public MapletNode(StateNode par, EdgeName realName, Model.Element elt)
  329. : base(par, realName, elt)
  330. {
  331. }
  332. }
  333. class VariableNode : ElementNode
  334. {
  335. public bool updatedHere;
  336. public string realName;
  337. public VariableNode(StateNode par, string realName, Model.Element elt)
  338. : base(par, realName, elt)
  339. {
  340. this.realName = realName;
  341. name = new EdgeName(vm.GetUserVariableName(realName));
  342. }
  343. }
  344. }