summaryrefslogtreecommitdiff
path: root/Source/ModelViewer/VccProvider.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Source/ModelViewer/VccProvider.cs')
-rw-r--r--Source/ModelViewer/VccProvider.cs3052
1 files changed, 1526 insertions, 1526 deletions
diff --git a/Source/ModelViewer/VccProvider.cs b/Source/ModelViewer/VccProvider.cs
index ae062c93..345dfda5 100644
--- a/Source/ModelViewer/VccProvider.cs
+++ b/Source/ModelViewer/VccProvider.cs
@@ -1,1526 +1,1526 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Microsoft.Boogie.ModelViewer.Vcc
-{
- public class Provider : ILanguageProvider
- {
- public static Provider Instance = new Provider();
- private Provider() { }
-
- public bool IsMyModel(Model m)
- {
- return m.TryGetFunc("$is_ghost_field") != null && m.TryGetFunc("$fk_vol_version") != null;
- }
-
- public ILanguageSpecificModel GetLanguageSpecificModel(Model m, ViewOptions opts)
- {
- var vm = new VccModel(m, opts);
- return vm;
- }
- }
-
- enum DataKind
- {
- Flat,
- PhysPtr,
- SpecPtr,
- Object,
- Ptrset,
- Map
- }
-
- class VccModel : LanguageModel
- {
- public readonly Model.Func f_ptr_to, f_phys_ptr_cast, f_spec_ptr_cast, f_mathint, f_local_value_is, f_spec_ptr_to, f_heap, f_select_field,
- f_select_value, f_field, f_field_type, f_int_to_ptr, f_ptr_to_int, f_ptr, f_map_t, f_select_ptr,
- f_owners, f_closed, f_roots, f_timestamps, f_select_bool, f_select_int, f_is_null, f_good_state,
- f_int_to_version, f_int_to_ptrset, f_set_in0, f_is_ghost_field, f_is_phys_field, f_idx,
- f_is_sequential_field, f_is_volatile_field, f_type_project_0, f_array, f_active_option, f_int_to_field,
- f_blob_type, f_array_emb, f_addr, f_address_root, f_base, f_field_arr_size, f_field_arr_root, f_field_arr_index,
- f_dot, f_prim_emb;
- public readonly Model.Element tp_object, tp_mathint, tp_bool, tp_state, tp_ptrset, tp_heaptp;
- public readonly Model.Element elt_me, elt_null;
- Dictionary<Model.Element, string> typeName = new Dictionary<Model.Element, string>();
- Dictionary<Model.Element, string> literalName = new Dictionary<Model.Element, string>();
- Dictionary<Model.Element, Model.Element> guessedType = new Dictionary<Model.Element,Model.Element>();
- public List<StateNode> states = new List<StateNode>();
- public Dictionary<string, string> localVariableNames = new Dictionary<string, string>();
-
- Dictionary<Model.Element, string> datatypeLongName = new Dictionary<Model.Element, string>();
-
- Dictionary<int, string> fileNameMapping = new Dictionary<int, string>();
-
- public const string selfMarker = "\\self";
- public const int maxDatatypeNameLength = 5;
-
- public VccModel(Model m, ViewOptions opts)
- : base(m, opts)
- {
- f_ptr_to = m.MkFunc("$ptr_to", 1);
- f_spec_ptr_to = m.MkFunc("$spec_ptr_to", 1);
- f_phys_ptr_cast = m.MkFunc("$phys_ptr_cast", 2);
- f_spec_ptr_cast = m.MkFunc("$spec_ptr_cast", 2);
- f_mathint = m.MkFunc("^^mathint", 0);
- f_local_value_is = m.MkFunc("$local_value_is", 5);
- f_heap = m.MkFunc("$heap", 1);
- f_select_field = m.MkFunc("Select_[$field][$ptr]$int", 2);
- f_select_value = m.MkFunc("Select_[$ptr]$int", 2);
- f_select_ptr = m.MkFunc("Select_[$ptr]$ptr", 2);
- f_select_int = m.MkFunc("Select_[$ptr]$int", 2);
- f_select_bool = m.MkFunc("Select_[$ptr]$bool", 2);
- f_owners = m.MkFunc("$f_owner", 1);
- f_closed = m.MkFunc("$f_closed", 1);
- f_roots = m.MkFunc("$roots", 1);
- f_timestamps = m.MkFunc("$f_timestamp", 1);
- f_active_option = m.MkFunc("$f_active_option", 1);
- f_field = m.MkFunc("$field", 1);
- f_field_type = m.MkFunc("$field_type", 1);
- f_int_to_ptr = m.MkFunc("$int_to_ptr", 1);
- f_ptr_to_int = m.MkFunc("$ptr_to_int", 1);
- f_ptr = m.MkFunc("$ptr", 2);
- f_dot = m.MkFunc("$dot", 2);
- f_map_t = m.MkFunc("$map_t", 2);
- f_is_null = m.MkFunc("$is_null", 1);
- f_good_state = m.MkFunc("$good_state", 1);
- f_int_to_version = m.MkFunc("$int_to_version", 1);
- f_int_to_ptrset = m.MkFunc("$int_to_ptrset", 1);
- f_int_to_field = m.MkFunc("$int_to_field", 1);
- f_set_in0 = m.MkFunc("$set_in0", 2);
- f_is_ghost_field = m.MkFunc("$is_ghost_field", 1);
- f_is_phys_field = m.MkFunc("$is_phys_field", 1);
- f_idx = m.MkFunc("$idx", 2);
- f_is_sequential_field = m.MkFunc("$is_sequential_field", 1);
- f_is_volatile_field = m.MkFunc("$is_volatile_field", 1);
- f_type_project_0 = m.MkFunc("$type_project_0", 1);
- f_array = m.MkFunc("$array", 2);
- f_blob_type = m.MkFunc("$blob_type", 1);
- f_array_emb = m.MkFunc("$array_emb", 2);
- f_addr = m.MkFunc("$addr", 1);
- f_base = m.MkFunc("$base", 1);
- f_prim_emb = m.MkFunc("$prim_emb", 1);
- f_address_root = m.MkFunc("$address_root", 2);
- f_field_arr_index = m.MkFunc("$field_arr_index", 1);
- f_field_arr_size = m.MkFunc("$field_arr_size", 1);
- f_field_arr_root = m.MkFunc("$field_arr_root", 1);
-
- tp_bool = m.GetFunc("^^bool").GetConstant();
- tp_mathint = m.GetFunc("^^mathint").GetConstant();
- tp_object = m.GetFunc("^^object").GetConstant();
- tp_state = m.GetFunc("^$#state_t").GetConstant();
- tp_ptrset = m.GetFunc("^$#ptrset").GetConstant();
-
- tp_heaptp = m.MkFunc("$heap_type", 0).GetConstant();
-
- elt_me = m.GetFunc("$me").GetConstant();
- elt_null = m.GetFunc("$null").GetConstant();
-
- literalName[elt_me] = "\\me";
- literalName[elt_null] = "NULL";
- foreach (var tpl in f_phys_ptr_cast.Apps) {
- if (tpl.Args[0] == elt_null)
- literalName[tpl.Result] = "(" + TypeName(tpl.Args[1]) + "*)NULL";
- }
- foreach (var tpl in f_spec_ptr_cast.Apps) {
- if (tpl.Args[0] == elt_null)
- literalName[tpl.Result] = "(" + TypeName(tpl.Args[1]) + "^)NULL";
- }
- foreach (var fn in model.Functions) {
- if (fn.Arity == 0 && fn.Name.StartsWith("l#"))
- literalName[fn.GetConstant()] = ":" + fn.Name.Substring(2);
- }
-
- DecodeFileNames();
- ComputeLocalVariableNames();
-
- foreach (var s in m.States) {
- var sn = new StateNode(this, s);
- sn.SetupVars();
- states.Add(sn);
- }
-
- var allStates = states.ToArray();
- if (allStates.Length == 1 && allStates[0].vars.Count == 0) {
- throw new Exception("This VCC model doesn't contain any variables. Was it saved with the -bvd option?");
- }
- states.Clear();
- var i = 0;
- while (i < allStates.Length) {
- var lastGoodName = allStates[i].State.Name;
-
- var userVars = new HashSet<string>(allStates[i].State.Variables.Where(localVariableNames.ContainsKey));
- i++;
- while (i < allStates.Length) {
- foreach (var v in allStates[i].State.Variables) {
- if (v == "$s" || userVars.Contains(v)) goto stop;
- if (localVariableNames.ContainsKey(v))
- userVars.Add(v);
- }
-
- var curName = TryParseSourceLocation(allStates[i].State.Name);
- if (!IsBadName(curName))
- lastGoodName = allStates[i].State.Name;
- i++;
- }
-
- stop:
-
- var lastState = allStates[i - 1];
- lastState.capturedStateName = lastGoodName;
- lastState.index = states.Count;
- states.Add(lastState);
- lastState.SetupVars();
- }
-
- foreach (var s in states) {
- var elt = s.State.TryGet("$s");
- if (elt != null)
- literalName[elt] = "\\state'" + s.index;
- }
-
- GenerateSourceLocations(states);
- }
-
-
- bool IsBadName(SourceLocation l)
- {
- return l == null || l.Filename.StartsWith("<");
- }
-
- private void ComputeLocalVariableNames()
- {
- var vars = model.States.SelectMany(s => s.Variables).Where(v => v != null).Distinct();
- Func<string, string> simpleName = s => { string dummy; return GetUserVariableNameCore(s, out dummy); };
- var userVars = vars.Where(s => simpleName(s) != null);
- var conflictsName = Conflicts(userVars, simpleName).ToArray();
- Func<string, string> qName = s => { string kind, n = GetUserVariableNameCore(s, out kind); return n + " (" + kind + ")"; };
- var conflictsKind = Conflicts(conflictsName, qName).ToArray();
-
- var conflictsNameH = new HashSet<string>(conflictsName);
- var conflictsKindH = new HashSet<string>(conflictsKind);
-
- foreach (var v in userVars) {
- if (conflictsKindH.Contains(v)) continue;
- if (conflictsNameH.Contains(v))
- localVariableNames[v] = qName(v);
- else
- localVariableNames[v] = simpleName(v);
- }
-
- var idx = 0;
- foreach (var v in conflictsKind) {
- localVariableNames[v] = string.Format("{0} #{1}", qName(v), idx++);
- }
- }
-
- static IEnumerable<A> Conflicts<A, B>(IEnumerable<A> input, Func<A, B> f)
- {
- var revMap = new Dictionary<B, A>();
- var reported = new HashSet<A>();
-
- foreach (var k in input) {
- if (reported.Contains(k)) continue;
- var v = f(k);
- A tmp;
- if (revMap.TryGetValue(v, out tmp) && !tmp.Equals(k)) {
- if (!reported.Contains(tmp)) {
- yield return tmp;
- reported.Add(tmp);
- }
- yield return k;
- reported.Add(k);
- } else {
- revMap[v] = k;
- }
- }
- }
-
- #region Function name scoring
- static string[][] prefixes = new string[][] {
- new string[] { "F#", "$eq.$map", "Q#", },
- new string[] { "F#lambda", },
- new string[] { "$int_to_", "lambda@", "distinct-aux-f", "Select_","Store_", "$select.", "$store.", },
- };
-
- static string[][] totals = new string[][] {
- new string[] {
- "$current_timestamp",
- "$full_stop", "$function_entry", "$ptr_to_i4",
- "$ptr_to_i8", "$ptr_to_u4", "$ptr_to_u8",
- "$span", "$sizeof", "$in_domain",
- "$inv2",
- "$is_claimable",
- "$set_cardinality", "$set_difference", "$set_union",
- "$thread_local", "$unchecked", "$writes_at",
- "$array_range", "$arrays_disjoint",
- "$byte_ptr_subtraction",
- },
-
- new string[] {
- "$addr", "$dot", "$emb0", "$fetch_from_domain", "$in_range_phys_ptr",
- "$in_range_spec_ptr", "$is_sequential_field", "$is_volatile_field",
- "$is_ghost_field", "$is_phys_field", "$is_math_type", "$invok_state",
- "$is_primitive",
- "$spec_ptr_cast",
- "$phys_ptr_cast",
- "$is_null",
- "$in_domain_lab",
- "$inv_lab",
- "$set_in0",
- },
-
- new string[] {
- "$_pow2", "$as_composite_field", "$as_field_with_type", "$as_in_range_t",
- "$as_primitive_field", "$base", "$call_transition", "tickleBool", "Ctor",
- "$mv_state", "$field", "$field_arr_root", "$field_kind", "$field_offset",
- "$field_parent_type", "$field_type", "$file_name_is", "$good_state",
- "$good_state_ext", "$function_arg_type", "$has_field_at0", "$map_domain",
- "$map_range", "$map_t", "$ptr_to", "$ptr_to_i1", "$ptr_to_i2",
- "$ptr_to_u1", "$ptr_to_u2", "$is_unwrapped", "$is_unwrapped_dynamic",
- "$heap", "$closed", "$owner", "$owns", "$modifies", "$post_unwrap",
- "$pow2", "$pre_unwrap", "$ptr", "$is", "$in_range_t", "$roots",
- "$timestamp", "$type_branch", "$type_code_is", "$type_project_0",
- "$typemap", "$set_in_pos", "$updated_owns", "$ver_domain", "$vs_state",
- "$set_singleton",
- "$f_owner", "$f_closed", "$f_timestamps",
- "$local_value_is",
- "$field_arr_ctor",
- "$idx",
- },
- };
-
- string[] state_props = new string[] { };
-
- Dictionary<string, int> functionScores = new Dictionary<string, int>();
-
- int FunctionScore(string name)
- {
- if (functionScores.Count == 0) {
- for (int i = 0; i < totals.Length; ++i)
- foreach (var s in totals[i])
- functionScores[s] = i;
- }
-
- int res;
- if (functionScores.TryGetValue(name, out res))
- return res;
-
- res = -1;
- if (name[0] == '$' && name.EndsWith("_to_int"))
- res = 1;
- else if (name.EndsWith("#frame"))
- res = 2;
- else if (name.Contains("#limited#"))
- res = 2;
- else {
- for (int i = 0; i < prefixes.Length; ++i)
- foreach (var p in prefixes[i])
- if (name.StartsWith(p)) {
- res = i;
- //goto stop;
- }
- //stop: ;
- }
-
- if (res == -1)
- res = 1; // default
-
- functionScores[name] = res;
- return res;
- }
- #endregion
-
- private void DecodeFileNames()
- {
- var fis = model.GetFunc("$file_name_is");
- foreach (var f in model.Functions) {
- if (f.Arity == 0 && f.Name.StartsWith("#file^")) {
- var sb = new StringBuilder();
- var idx = 6;
- var name = f.Name;
- while (idx < name.Length) {
- if (name[idx] == '?') {
- var c = (char)Int32.Parse(name.Substring(idx + 1, 2), System.Globalization.NumberStyles.HexNumber);
- sb.Append(c);
- idx += 3;
- } else {
- sb.Append(name[idx++]);
- }
- }
- name = sb.ToString();
-
- foreach (var app in fis.AppsWithArg(1, f.GetConstant()))
- fileNameMapping[app.Args[0].AsInt()] = name;
- }
- }
- }
-
- private Model.Element DecodeDT(string dt)
- {
- if (dt.StartsWith("dt")) {
- var tpName = dt.Replace("dt", "#distTp");
- var f = model.TryGetFunc(tpName);
- if (f != null) {
- return f.GetConstant();
- //var res = f_type_project_0.TryEval(ptr);
- //if (res != null)
- // tp = res;
- }
- }
- return null;
- }
-
- private string DecodeToken(string name, ref Model.Element tp)
- {
- var idx = name.LastIndexOf("$");
- if (idx < 0) return null;
- var words = name.Substring(idx + 1).Split('.', '^', '!', '#', '@');
- if (words.Length > 3)
- tp = DecodeDT(words[3]);
- return string.Format("{0}({1},{2})", fileNameMapping[int.Parse(words[0])], words[1], words[2]);
- }
-
- public string GetUserVariableName(string name)
- {
- string res;
- localVariableNames.TryGetValue(name, out res);
- return res;
- }
-
-
- string GetUserVariableNameCore(string name, out string kind)
- {
- if (name.StartsWith("L#")) {
- kind = "local";
- return name.Substring(2);
- }
-
- if (name.StartsWith("P#")) {
- kind = "in-param";
- return name.Substring(2);
- }
-
- if (name.StartsWith("OP#")) {
- kind = "out-param";
- return name.Substring(3);
- }
-
- if (name.StartsWith("SL#")) {
- kind = "spec local";
- return name.Substring(3);
- }
-
- if (name.StartsWith("SP#")) {
- kind = "spec in-param";
- return name.Substring(3);
- }
-
- if (name.StartsWith("local.")) {
- kind = "param copied to local";
- return name.Substring(6);
- }
-
- if (name.StartsWith("addr.")) {
- kind = "stack-allocated struct";
- return name.Substring(5);
- }
-
- if (name == "$result") {
- kind = "function return value";
- return "\\result";
- }
-
- if (name.StartsWith("res__") && viewOpts.ViewLevel >= 1) {
- kind = "call result";
- return name;
- }
-
- if (name == "$s" && viewOpts.ViewLevel >= 1) {
- kind = "current state";
- return "\\now";
- }
-
- kind = null;
- return null;
- }
-
-
- private string LiteralName(Model.Element elt)
- {
- string r;
-
- if (literalName.TryGetValue(elt, out r))
- return r;
-
- r = TryTypeName(elt);
- if (r != null) {
- literalName[elt] = r;
- return r;
- }
-
- var i = elt as Model.Integer;
- if (i != null)
- return AsPow2(i);
-
- var bv = elt as Model.BitVector;
- if (bv != null)
- return bv.Numeral + "bv" + bv.Size.ToString();
-
- return null;
- }
-
- public Model.Element LocalType(string localName)
- {
- string dummy;
- var v = GetUserVariableNameCore(localName, out dummy);
- if (v == null) v = localName;
- var c = model.TryGetFunc("#loc." + v);
- if (c != null) {
- var localIs = f_local_value_is.AppWithArg(2, c.GetConstant());
- if (localIs != null)
- return localIs.Args[4];
- }
- foreach (var s in model.States.Reverse()) {
- var val = s.TryGet(localName);
- var tp = GuessType(val);
- if (tp != tp_mathint)
- return tp;
- }
- return tp_mathint;
- }
-
- public Model.Element Image(Model.Element elt, Model.Func f)
- {
- var r = f.AppWithResult(elt);
- if (r != null)
- return r.Args[0];
- return null;
- }
-
- string TypeNameCore(Model.Element elt)
- {
- var deref = Image(elt, f_ptr_to);
- if (deref != null)
- return TypeName(deref) + "*";
- deref = Image(elt, f_spec_ptr_to);
- if (deref != null)
- return TypeName(deref) + "^";
- deref = Image(elt, f_blob_type);
- if (deref != null)
- return "_(blob " + CanonicalName(deref) + ")";
- var mapt = f_map_t.AppWithResult(elt);
- if (mapt != null)
- return string.Format("{1}[{0}]", TypeName(mapt.Args[0]), TypeName(mapt.Args[1]));
-
- var arr = f_array.AppWithResult(elt);
- if (arr != null) {
- return string.Format("{0}[{1}]", TypeName(arr.Args[0]), arr.Args[1].ToString());
- }
-
- foreach (var app in elt.Names)
- if (app.Func.Arity == 0 && app.Func.Name.StartsWith("^")) {
- var n = app.Func.Name.Substring(1);
- switch (n) {
- case "^i1": return "int8_t";
- case "^u1": return "uint8_t";
- case "^i2": return "int16_t";
- case "^u2": return "uint16_t";
- case "^i4": return "int32_t";
- case "^u4": return "uint32_t";
- case "^i8": return "int64_t";
- case "^u8": return "uint64_t";
- case "^bool": return "bool";
- default:
- var pref = "_vcc_math_type_";
- if (n.StartsWith(pref)) n = n.Substring(pref.Length);
- return n;
- }
- }
-
- return null;
- }
-
- public string TypeName(Model.Element elt)
- {
- var r = TryTypeName(elt);
- if (r == null)
- return elt.ToString();
- else return r;
- }
-
- public string TryTypeName(Model.Element elt)
- {
- string res;
- if (!typeName.TryGetValue(elt, out res)) {
- typeName[elt] = elt.ToString(); // avoid infinite recursion
- res = TypeNameCore(elt);
- typeName[elt] = res;
- }
- return res;
- }
-
- public static readonly string[] synthethic_fields = new string[] { "$f_owns", "$f_ref_cnt", "$f_vol_version", "$f_root", "$f_group_root", "$f_active_option" };
-
- public string ConstantFieldName(Model.Element elt)
- {
- string res;
- IsConstantField(elt, out res);
- return res;
- }
-
- public bool IsConstantField(Model.Element elt)
- {
- string dummy;
- return IsConstantField(elt, out dummy);
- }
-
- public bool IsConstantField(Model.Element elt, out string theName)
- {
- var bestScore = int.MinValue;
- string bestName = null;
-
- foreach (var t in elt.Names) {
- var score = int.MinValue;
- string name = null;
- if (t.Args.Length == 0) {
- name = t.Func.Name;
- score = 0;
- var dotIdx = name.IndexOf('.');
- if (dotIdx > 0) {
- score += 10;
- name = name.Substring(dotIdx + 1);
- }
- if (name.Contains('#')) score -= 1;
- } else if (t.Func.Name.StartsWith("$f_") && synthethic_fields.Contains(t.Func.Name)) {
- name = string.Format("{0}<{1}>", t.Func.Name.Substring(3).Replace("root", "alloc_root"), TypeName(t.Args[0]));
- score = 6;
- } else if (t.Func == f_array_emb) {
- name = string.Format("[0] (of {0}[{1}])", TypeName(t.Args[0]), t.Args[1].ToString());
- score = 5;
- }
- if (score > bestScore) {
- bestScore = score;
- bestName = name;
- }
- }
-
- theName = bestName;
- return bestScore >= 5;
- }
-
- bool IsSomeState(Model.Element elt)
- {
- var tp = GuessType(elt);
- return tp == tp_state || tp == tp_heaptp;
- }
-
- bool IsThisState(Model.Element st, Model.Element elt)
- {
- return elt == st || elt == f_heap.TryEval(st);
- }
-
- Model.Element GuessType(Model.Element element)
- {
- Model.Element res;
- if (!guessedType.TryGetValue(element, out res)) {
- res = GuessTypeCore(element);
- guessedType[element] = res;
- }
- return res;
- }
-
- Model.Element GuessTypeCore(Model.Element element)
- {
- if (element is Model.Boolean)
- return tp_bool;
-
- var fld = f_field.TryEval(element);
- if (fld != null) {
- var tp = f_field_type.TryEval(fld);
- if (tp != null) {
- var ptp = f_ptr_to.TryEval(tp);
- if (ptp != null)
- return ptp;
- ptp = f_spec_ptr_to.TryEval(tp);
- if (ptp != null)
- return ptp;
- }
- return tp_object;
- }
-
- foreach (var tpl in element.References) {
- if (element == tpl.Result) {
- if (tpl.Func == f_ptr)
- return tp_object;
- if (tpl.Func == f_heap)
- return tp_heaptp;
- }
-
- if (tpl.Args.Length >= 1 && tpl.Args[0] == element) {
- if (tpl.Func == f_heap || tpl.Func == f_closed || tpl.Func == f_good_state)
- return tp_state;
- }
-
- if (tpl.Func == f_select_bool)
- if (tpl.Args[0] == element)
- return tp_ptrset;
- else if (tpl.Args[1] == element)
- return tp_object;
-
- var fname = tpl.Func.Name;
-
- if (tpl.Args.Length == 2 && tpl.Args[0] == element && fname.StartsWith("$select.$map_t")) {
- var mt = model.TryGetFunc("MT#" + fname);
- if (mt != null && mt.Arity == 0)
- return mt.GetConstant();
- var t1 = GuessType(tpl.Args[1]);
- var t2 = GuessType(tpl.Result);
- var t = f_map_t.TryEval(t1, t2);
- if (t != null)
- return t;
- }
-
- var tpName = DataTypeName(element, tpl);
- if (tpName != null) {
- var tp = model.TryGetFunc("^$#" + tpName);
- if (tp != null)
- return tp.GetConstant();
- }
- }
-
- return tp_mathint;
- }
-
- string DataTypeName(Model.Element elt, Model.FuncTuple tpl)
- {
- var fname = tpl.Func.Name;
- if (tpl.Args.Length == 1 && tpl.Args[0] == elt && fname.StartsWith("RF#")) {
- var fldName = tpl.Func.Name.Substring(3);
- var idx = fldName.LastIndexOf('.');
- if (idx > 0) {
- return fldName.Substring(0, idx).Replace("_vcc_math_type_", "");
- }
- }
-
- if (tpl.Args.Length == 1 && tpl.Args[0] == elt && (fname.StartsWith("DSZ#") || fname.StartsWith("RSZ#") || fname.StartsWith("DGH#"))) {
- return fname.Substring(4).Replace("_vcc_math_type_", "");
- }
- return null;
- }
-
- public DataKind GetKind(Model.Element tp, out Model.FuncTuple tpl)
- {
- tpl = null;
-
- if (tp == tp_object)
- return DataKind.Object;
- else if (tp == tp_ptrset)
- return DataKind.Ptrset;
-
- tpl = f_ptr_to.AppWithResult(tp);
- if (tpl != null) return DataKind.PhysPtr;
- tpl = f_spec_ptr_to.AppWithResult(tp);
- if (tpl != null) return DataKind.SpecPtr;
- tpl = f_map_t.AppWithResult(tp);
- if (tpl != null) return DataKind.Map;
-
- return DataKind.Flat;
- }
-
- public DataKind GetKind(Model.Element tp)
- {
- Model.FuncTuple dummy;
- return GetKind(tp, out dummy);
- }
-
-
- public Model.Element WrapForUse(Model.Element elt, Model.Element tp)
- {
- Model.FuncTuple tpl;
- var kind = GetKind(tp, out tpl);
-
- if (kind == DataKind.Flat) {
- if (elt.Kind == Model.ElementKind.Integer) {
- var tpname = TypeName(tp);
- if(tpname.StartsWith("$")) tpname = tpname.Substring(1);
- if (tpname.StartsWith("#")) {
- foreach (var tupl in elt.References) {
- if (tupl.Args.Length == 1 && tupl.Args[0] == elt && tupl.Func.Name.StartsWith("$int_to_") && tupl.Func.Name.EndsWith(tpname)) {
- return tupl.Result;
- }
- }
- }
- }
- return elt;
- }
-
- if (kind == DataKind.Map) {
- if (elt.Kind == Model.ElementKind.Integer) {
- Model.Element theMap = null;
- foreach (var conv in model.Functions)
- // really, we should reconstruct the name of this function, but this is painful
- if (conv.Arity == 1 && conv.Name.StartsWith("$int_to_map_t")) {
- var app = conv.AppWithArg(0, elt);
- if (app != null) {
- theMap = app.Result;
- break;
- }
- }
- if (theMap == null) return elt;
- return theMap;
- }
- return elt;
- } else if (kind == DataKind.Ptrset) {
- var tmp = f_int_to_ptrset.TryEval(elt);
- if (tmp != null)
- return tmp;
- return elt;
- }
-
- if (kind == DataKind.PhysPtr || kind == DataKind.SpecPtr || kind == DataKind.Object) {
- if (elt.Kind == Model.ElementKind.Integer) {
- var tmp = f_int_to_ptr.TryEval(elt);
- if (tmp != null)
- elt = tmp;
- }
- }
-
- if (kind == DataKind.Object)
- return elt;
-
- if (kind == DataKind.PhysPtr)
- return Util.OrElse(f_phys_ptr_cast.TryEval(elt, tpl.Args[0]), elt);
-
- if (kind == DataKind.SpecPtr)
- return Util.OrElse(f_spec_ptr_cast.TryEval(elt, tpl.Args[0]), elt);
-
- Util.Assert(false);
- return elt;
- }
-
- void AddSpecialField(StateNode state, Model.Element elt, List<ElementNode> res, string name, Model.Func select_map)
- {
- if (elt == null) return;
-
- var map = state.State.TryGet("$s");
- if (map != null)
- map = select_map.TryEval(map);
- if (map != null) {
- var model = elt.Model;
- Model.Element val = f_select_bool.TryEval(map, elt);
- Model.Element tp = tp_bool;
- if (val == null) {
- val = f_select_ptr.TryEval(map, elt);
- tp = tp_object;
- }
- if (val == null) {
- val = f_select_int.TryEval(map, elt);
- tp = tp_mathint;
- }
- if (val != null) {
- res.Add(new FieldNode(state, new EdgeName(name), val, tp) { Category = NodeCategory.MethodologyProperty });
- }
- }
- }
-
- void AddPointerFunction(StateNode state, Model.Element elt, List<ElementNode> res, string name, Model.Func fn, Model.Element tp)
- {
- if (elt == null) return;
-
- var val = fn.TryEval(elt);
- if (val != null) {
- res.Add(new FieldNode(state, new EdgeName(name), val, tp) { Category = NodeCategory.MethodologyProperty });
- }
- }
-
- void AddPtrType(StateNode state, Model.Element elt, List<ElementNode> res)
- {
- var f = f_field.TryEval(elt);
- if (f == null) return;
-
- var tp = f_field_type.TryEval(f);
-
- var seq = "";
-
- var is_seq = f_is_sequential_field.TryEval(f) as Model.Boolean;
- var is_vol = f_is_volatile_field.TryEval(f) as Model.Boolean;
-
- if (is_seq != null && is_vol != null && is_seq.Value == is_vol.Value) {
- seq = " (volatile/sequential mismatch)";
- } else if ((is_seq != null && is_seq.Value) || (is_vol != null && !is_vol.Value)) {
- seq = " (sequential)";
- } else if ((is_seq != null && !is_seq.Value) || (is_vol != null && is_vol.Value)) {
- seq = " (volatile)";
- }
-
- if (tp != null || seq != "") {
- res.Add(new FieldNode(state, new EdgeName("\\typeof" + seq), tp, tp_mathint) { Category = NodeCategory.MethodologyProperty });
- }
- }
-
- string SkolemName(Model.Func f, ref Model.Element tp)
- {
- if (f.Name.IndexOf('!') > 0) {
- var tok = DecodeToken(f.Name, ref tp);
- if (tok != null) {
- var baseName = f.Name.Substring(0, f.Name.LastIndexOf('$'));
- if (baseName.StartsWith("Q#"))
- baseName = baseName.Substring(2);
- return string.Format("{0}@{1}", baseName, ShortenToken(tok, 10, false));
- }
- }
- return null;
- }
-
- string GlobalName(Model.Func f, ref Model.Element tp)
- {
- if (f.Name.StartsWith("G#")) {
- var idx = f.Name.LastIndexOf("#dt");
- if (idx < 0) return null;
- var name = f.Name.Substring(2, idx - 2);
- tp = DecodeDT(f.Name.Substring(idx + 1));
- return string.Format("::{0}", name);
- }
- return null;
- }
-
-
- public IEnumerable<ElementNode> CommonNodes(StateNode state)
- {
- var skolems = new List<ElementNode>();
-
- Model.Element tp = null;
-
- foreach (var f in model.Functions) {
- if (f.Arity != 0) continue;
- var s = SkolemName(f, ref tp);
- if (s == null)
- s = GlobalName(f, ref tp);
- if (s != null) {
- if (tp == null)
- tp = GuessType(f.GetConstant());
- var val = WrapForUse(f.GetConstant(), tp);
- skolems.Add(new VariableNode(state, s, val, tp));
- }
- }
-
- return skolems;
- }
-
- private Model.Element GuessPtrTo(Model.Element tp)
- {
- var p = f_ptr_to.TryEval(tp);
- if (p != null) return p;
- p = f_spec_ptr_to.TryEval(tp);
- if (p != null) return p;
- var nm = model.MkFunc("*ptrto_" + TypeName(tp), 0).GetConstant();
- f_ptr_to.AddApp(nm, tp);
- return f_ptr_to.TryEval(tp);
- }
-
- private Model.Element PtrTo(Model.Element tp, Model.Func f_ptr_to)
- {
- var p = f_ptr_to.TryEval(tp);
- if (p != null) return p;
- var nm = model.MkFunc("*" + f_ptr_to.Name + "_" + TypeName(tp), 0).GetConstant();
- f_ptr_to.AddApp(nm, tp);
- return f_ptr_to.TryEval(tp);
- }
-
- private bool IsArrayField(Model.Element ptr)
- {
- return ptr != null && f_idx.TryEval(ptr, model.TryMkElement("0")) != null;
- }
-
- public IEnumerable<ElementNode> GetExpansion(StateNode state, Model.Element elt, Model.Element tp)
- {
- List<ElementNode> result = new List<ElementNode>();
- Model.FuncTuple tpl;
-
- if (elt == null) return result;
-
- var kind = GetKind(tp, out tpl);
- if (kind == DataKind.PhysPtr || kind == DataKind.SpecPtr || kind == DataKind.Object) {
- var heap = state.State.TryGet("$s");
- if (heap != null)
- heap = f_heap.TryEval(heap);
- var addresses = new HashSet<Model.Element>();
-
- if (heap != null) {
- var basePtr = f_base.TryEval(elt);
- foreach (var fld in f_select_field.AppsWithArg(0, heap)) {
- var val = f_select_value.TryEval(fld.Result, elt);
- if (val != null) {
- var field = fld.Args[1];
- if (!IsConstantField(field) && viewOpts.ViewLevel <= 2)
- continue;
- var addr = f_dot.TryEval(elt, field);
- if (addr != null) addresses.Add(addr);
- var node = ComputeUnionActiveOption(state, elt, val, field);
- if (node != null)
- result.Add(node);
- else
- BuildFieldNode(result, state, addr, field, val, addr);
- }
- }
- //result.Sort(CompareFields);
- }
-
- {
- foreach (var app in f_idx.AppsWithArg(0, elt)) {
- var addr = app.Result;
- Model.Element val = null, atp = tp;
-
- addresses.Add(addr);
-
- foreach (var papp in f_dot.AppsWithResult(addr)) {
- var tmp = f_select_value.OptEval(f_select_field.OptEval(heap, papp.Args[1]), papp.Args[0]);
- if (tmp != null) {
- val = tmp;
- var tt = f_field_type.TryEval(papp.Args[1]);
- if (tt != null) atp = tt;
- }
- }
-
- if (val != null)
- val = WrapForUse(val, atp);
- result.Add(new MapletNode(state, new EdgeName(this, "[%0]", app.Args[1]), val, atp) { Category = NodeCategory.Maplet });
- if (addr != null)
- result.Add(new MapletNode(state, new EdgeName(this, "&[%0]", app.Args[1]), addr, GuessPtrTo(atp)) { Category = NodeCategory.Maplet });
- }
- }
-
- foreach (var ptr in f_dot.AppsWithArg(0, elt)) {
- if (addresses.Contains(ptr.Result)) continue;
- var fld = ptr.Args[1];
- var idx = f_field_arr_index.TryEval(fld);
- if (idx != null) {
- var xtp = f_field_type.TryEval(fld);
- result.Add(new MapletNode(state, new EdgeName(this, "&[%0] of %1", idx, f_field_arr_size.TryEval(fld)), ptr.Result, GuessPtrTo(xtp)) { Category = NodeCategory.Maplet });
- }
- if (!IsConstantField(ptr.Args[1])) continue;
- BuildFieldNode(result, state, ptr.Result, ptr.Args[1], null, ptr.Result);
- }
-
- AddSpecialField(state, elt, result, "\\closed", f_closed);
- AddSpecialField(state, elt, result, "\\owner", f_owners);
- AddSpecialField(state, elt, result, "\\root", f_roots);
- AddSpecialField(state, elt, result, "\\timestamp", f_timestamps);
- AddPointerFunction(state, elt, result, "\\embedding", f_prim_emb, tp_object);
- AddPointerFunction(state, elt, result, "\\addr", f_addr, tp_mathint);
-
- if (viewOpts.ViewLevel >= 1) {
- AddPtrType(state, elt, result);
- AddCasts(state, elt, result);
- var sets = new SetsNode(state, elt);
- if (!sets.IsEmpty)
- result.Add(sets);
- }
-
- } else if (kind == DataKind.Map) {
- var elTp = tpl.Args[1];
- foreach (var sel in model.Functions)
- if (sel.Arity == 2 && sel.Name.StartsWith("$select.$map_t")) {
- foreach (var app in sel.AppsWithArg(0, elt)) {
- var val = WrapForUse(app.Result, elTp);
- var edgname = new EdgeName(this, "[%0]", app.Args[1]);
- result.Add(new MapletNode(state, edgname, val, elTp) { Category = NodeCategory.Maplet });
- }
- }
- } else if (kind == DataKind.Ptrset) {
- foreach (var sel in f_select_bool.AppsWithArg(0, elt)) {
- var edgname = new EdgeName(this, "[%0]", sel.Args[1]);
- result.Add(new MapletNode(state, edgname, sel.Result, tp_bool) { Category = NodeCategory.Maplet });
- }
- } else if (kind == DataKind.Flat) {
- foreach (var tupl in elt.References) {
- if (tupl.Args.Length == 1 && tupl.Args[0] == elt) {
- var fname = tupl.Func.Name;
- var idx = fname.LastIndexOf('.');
- if (fname.StartsWith("RF#") && idx > 0) {
- fname = fname.Substring(idx + 1);
- } else if (fname.StartsWith("DP#p")) {
- fname = fname.Substring(4);
- idx = fname.IndexOf('#');
- if (idx > 0)
- fname = fname.Substring(idx + 1) + "#" + fname.Substring(0, idx);
- } else {
- fname = null;
- }
-
- if (fname != null)
- result.Add(new FieldNode(state, new EdgeName(fname), tupl.Result, GuessType(tupl.Result)) { Category = NodeCategory.SpecField });
- }
- }
- }
-
- if (!(elt is Model.Boolean)) {
- var curState = state.State.TryGet("$s");
-
- foreach (var tupl in elt.References) {
- {
- var seenSelf = false;
- var seenState = false;
- var seenThisState = false;
- var args = tupl.Args;
- for (int i = 0; i < args.Length; ++i) {
- if (args[i] == elt) seenSelf = true;
- if (IsThisState(curState, args[i])) seenThisState = true;
- else if (IsSomeState(args[i])) seenState = true;
- }
- if (!seenSelf) continue; // not looking for aliases (maybe we should?)
- if (seenState && !seenThisState) continue;
- }
-
- var argsFmt = new StringBuilder();
- var name = tupl.Func.Name;
-
- var score = FunctionScore(name);
- if (score >= viewOpts.ViewLevel)
- continue;
-
- var retTp = GuessType(tupl.Result);
- var retVal = tupl.Result;
-
- var cat = NodeCategory.MethodologyProperty;
- if (name.StartsWith("F#")) {
- name = name.Substring(2);
- cat = NodeCategory.UserFunction;
- }
-
- if (name.StartsWith("DF#")) {
- name = name.Substring(3);
- cat = NodeCategory.UserFunction;
- }
-
- if (name.StartsWith("$eq.$"))
- name = "EQ";
-
- {
- Model.Element sktp = null;
- var sk = SkolemName(tupl.Func, ref sktp);
- if (sk != null) {
- name = sk;
- if (sktp != null)
- retVal = WrapForUse(tupl.Result, sktp);
- cat = NodeCategory.Maplet;
- }
- }
-
- {
- argsFmt.Append(name).Append("(");
- var args = new List<Model.Element>();
- foreach (var a in tupl.Args) {
- if (IsThisState(curState, a))
- argsFmt.Append("\\now, ");
- else if (a == elt)
- argsFmt.Append(selfMarker + ", ");
- else {
- argsFmt.AppendFormat("%{0}, ", args.Count);
- args.Add(a);
- }
- }
- argsFmt.Length -= 2;
- argsFmt.Append(")");
- var edgeName = new EdgeName(this, argsFmt.ToString(), args.ToArray());
- result.Add(new MapletNode(state, edgeName, retVal, retTp) { ViewLevel = score, Category = cat });
- }
-
- }
- }
-
- return result;
- }
-
- private FieldNode ComputeUnionActiveOption(StateNode state, Model.Element elt, Model.Element val, Model.Element field)
- {
- if (f_active_option.AppsWithResult(field).FirstOrDefault() != null) {
- var activeOpt = f_dot.OptEval(elt, f_int_to_field.OptEval(val));
- if (activeOpt != null) {
- var nm = ConstantFieldName(field);
- var fieldNode = new FieldNode(state, new EdgeName(nm), activeOpt, GuessType(activeOpt)) { Category = NodeCategory.MethodologyProperty };
- return fieldNode;
- }
- }
- return null;
- }
-
- private void AddCasts(StateNode state, Model.Element elt, List<ElementNode> result)
- {
- foreach (var app in f_phys_ptr_cast.AppsWithArg(0, elt)) {
- if (app.Result != elt)
- result.Add(new MapletNode(state, new EdgeName(this, "(" + TypeName(app.Args[1]) + "*)..."), app.Result, PtrTo(app.Args[1], f_ptr_to)));
- }
- foreach (var app in f_spec_ptr_cast.AppsWithArg(0, elt)) {
- if (app.Result != elt)
- result.Add(new MapletNode(state, new EdgeName(this, "(" + TypeName(app.Args[1]) + "^)..."), app.Result, PtrTo(app.Args[1], f_spec_ptr_to)));
- }
- var addr = f_addr.TryEval(elt);
- if (addr != null) {
- foreach (var app in f_blob_type.Apps) {
- var blob = f_address_root.TryEval(addr, app.Result);
- if (blob != null) {
- result.Add(new MapletNode(state, new EdgeName(this, TypeName(app.Result) + "..."), blob, app.Result));
- }
- }
- }
- }
-
- private void BuildFieldNode(List<ElementNode> result, StateNode state, Model.Element ptr, Model.Element field, Model.Element val, Model.Element addr)
- {
- var ftp = f_field_type.TryEval(field);
- if (val != null)
- val = WrapForUse(val, ftp);
-
- if (IsArrayField(ptr)) {
- val = addr;
- addr = null;
- ftp = GuessPtrTo(ftp);
- }
-
- var nm = ConstantFieldName(field);
- var edgname = nm == null ? field.ToString() : nm;
-
- var cat = NodeCategory.PhysField;
- if (f_is_ghost_field.IsTrue(field))
- cat = NodeCategory.SpecField;
- if (nm != null && nm.Contains("<"))
- cat = NodeCategory.MethodologyProperty;
-
- var fieldNode = new FieldNode(state, new EdgeName(edgname), val, ftp) { Category = cat};
- result.Add(fieldNode);
-
- if (addr != null) {
- result.Add(new FieldNode(state, new EdgeName("&" + edgname), addr, GuessPtrTo(ftp)) { Category = cat });
- }
- }
-
- public override IEnumerable<IState> States
- {
- get
- {
- return states;
- }
- }
-
- private int DataTypeToString(StringBuilder sb, int level, Model.Element elt)
- {
- Model.FuncTuple ctor = null;
- int len = 1;
- string dataTypeType = null;
- foreach (var app in elt.References) {
- var n = app.Func.Name;
- if (app.Result == elt && n.StartsWith("DF#")) {
- ctor = app;
- }
- var tmp = DataTypeName(elt, app);
- if (tmp != null) dataTypeType = tmp;
- }
-
- if (dataTypeType != null) {
- if (ctor != null)
- sb.Append(ctor.Func.Name.Substring(3));
- else
- sb.Append(DataTypeShortName(elt, dataTypeType));
- if (ctor != null && ctor.Args.Length > 0) {
- if (level <= 0) sb.Append("(...)");
- else {
- sb.Append("(");
- for (int i = 0; i < ctor.Args.Length; ++i) {
- if (i != 0) sb.Append(", ");
- len += DataTypeToString(sb, level - 1, ctor.Args[i]);
- }
- sb.Append(")");
- }
- }
- } else {
- sb.Append(CanonicalName(elt));
- }
- return len;
- }
-
- private string DataTypeShortName(Model.Element elt, string tp)
- {
- var baseName = tp;
-
- var hd = model.MkFunc("DGH#" + tp, 1).TryEval(elt);
- if (hd != null) {
- foreach (var nm in hd.References) {
- if (nm.Func.Arity == 0 && nm.Func.Name.StartsWith("DH#"))
- baseName = nm.Func.Name.Substring(3);
- }
- }
-
- return baseName;
- }
-
- private string CanonicalBaseNameCore(string name, Model.Element elt, bool doDatatypes, ref NameSeqSuffix suff)
- {
- var vm = this;
-
- if (name.Contains("[") || name.Contains("'"))
- name = "";
-
- if (name != "")
- return name;
-
- var isNull = false;
- foreach (var tpl in elt.References) {
- var fn = tpl.Func;
- if (fn.Name.StartsWith("$select.$map_t") && fn.Arity == 2 && tpl.Args[0] == elt)
- return "map";
- if (fn.Name.StartsWith("$int_to_map_t") && tpl.Result == elt)
- return "map";
-
- if (fn.Arity >= 1 && tpl.Args[0] == elt) {
- if (fn == f_select_bool)
- return "ptrset";
- }
-
- if (tpl.Result == elt)
- if (fn == f_int_to_version)
- return "version";
-
- if (fn == f_is_null && tpl.Result == model.True)
- isNull = true;
-
- var dtpName = DataTypeName(elt, tpl);
- if (dtpName != null) {
- var sb = new StringBuilder();
- string prev = null;
- datatypeLongName[elt] = "*SELF*"; // in case we recurse (but this shouldn't happen)
- for (int lev = 0; lev < 10; lev++) {
- sb.Length = 0;
- var len = DataTypeToString(sb, lev, elt);
- if (prev == null || len <= maxDatatypeNameLength)
- prev = sb.ToString();
- }
-
- datatypeLongName[elt] = prev;
- suff = NameSeqSuffix.WhenNonZero;
- return prev;
- }
- }
-
- var fld = vm.f_field.TryEval(elt);
- if (fld != null) {
- var tp = vm.f_field_type.TryEval(fld);
- if (tp != null) {
- var n = vm.TryTypeName(tp);
- if (n != null) {
- if (isNull)
- return "(" + n + "*)NULL";
- return n;
- }
- }
- }
-
- return "";
- }
-
- protected override string CanonicalBaseName(Model.Element elt, out NameSeqSuffix suff)
- {
- var lit = this.LiteralName(elt);
- if (lit != null) {
- suff = NameSeqSuffix.None;
- return lit;
- }
- if (datatypeLongName.TryGetValue(elt, out lit)) {
- suff = NameSeqSuffix.WhenNonZero;
- return lit;
- }
-
- var name = base.CanonicalBaseName(elt, out suff);
- name = CanonicalBaseNameCore(name, elt, true, ref suff);
-
- return name;
- }
-
- public override string PathName(IEnumerable<IDisplayNode> path)
- {
- var sb = new StringBuilder();
- foreach (var d in path) {
- var name = d.Name;
- if (name == "") continue; // can that happen?
- if (name.Contains("(") && name.Contains(selfMarker)) {
- var repl = name.Replace(selfMarker, sb.ToString());
- sb.Length = 0;
- sb.Append(repl);
- } else {
- if (sb.Length > 0 && name[0] != '[')
- sb.Append("->");
- sb.Append(d.Name);
- }
- }
-
- return sb.ToString();
- }
- }
-
- class StateNode : NamedState
- {
- internal VccModel vm;
- internal List<VariableNode> vars;
- internal List<ElementNode> commons;
- internal int index;
- internal string capturedStateName;
-
- public StateNode(VccModel parent, Model.CapturedState s)
- : base(s, parent)
- {
- this.capturedStateName = s.Name;
- this.vm = parent;
- }
-
- internal void SetupVars()
- {
- if (vars != null) return;
- vars = new List<VariableNode>();
-
- var names = Util.Empty<string>();
-
- if (vm.states.Count > 0) {
- var prev = vm.states.Last();
- names = prev.vars.Map(v => v.realName);
- }
-
- names = names.Concat(state.Variables).Distinct();
-
- var curVars = state.Variables.ToDictionary(x => x);
- foreach (var v in names) {
- var localName = vm.GetUserVariableName(v);
- if (localName != null) {
- var tp = vm.LocalType(v);
- var val = state.TryGet(v);
- val = vm.WrapForUse(val, tp);
- var vn = new VariableNode(this, v, val, tp) { ShortName = localName };
- vn.updatedHere = vm.states.Count > 0 && curVars.ContainsKey(v);
- if (curVars.ContainsKey(v))
- vm.RegisterLocalValue(vn.Name, val);
- vars.Add(vn);
- }
- }
-
- vm.Flush(vars);
-
- commons = new List<ElementNode>();
- commons.AddRange(vm.CommonNodes(this));
- }
-
- public override IEnumerable<IDisplayNode> Nodes
- {
- get {
- return vars.Concat(commons);
- }
- }
-
- public override string CapturedStateName
- {
- get
- {
- return this.capturedStateName;
- }
- }
- }
-
- class ElementNode : DisplayNode
- {
- protected StateNode stateNode;
- protected Model.Element tp;
- protected VccModel vm { get { return stateNode.vm; } }
-
- public ElementNode(StateNode st, EdgeName name, Model.Element elt, Model.Element tp)
- : base(st.vm, name, elt)
- {
- this.stateNode = st;
- this.tp = tp;
- }
-
- protected override void ComputeChildren()
- {
- children.AddRange(vm.GetExpansion(stateNode, element, tp));
- }
-
- public override string ToolTip
- {
- get
- {
- var sb = new StringBuilder();
- if (tp != null)
- sb.AppendFormat("Type: {0}\n", vm.TypeName(tp));
- var i = element as Model.Integer;
- if (i != null) {
- var n = System.Numerics.BigInteger.Parse(i.Numeral);
- sb.AppendFormat("Value: {0} (0x{1:x})\n", n, n);
- } else if (element != null) {
- sb.AppendFormat("Value: {0}\n", element);
- }
- return sb.ToString();
- }
- }
- }
-
- class SetsNode : ElementNode
- {
- List<Model.Element> refs = new List<Model.Element>();
-
- public SetsNode(StateNode par, Model.Element elt)
- : base(par, new EdgeName("\\in ..."), null, null)
- {
- children = new List<IDisplayNode>();
- foreach (var app in vm.f_select_bool.AppsWithArg(1, elt)) {
- children.Add(
- new MapletNode(par, new EdgeName(vm, VccModel.selfMarker + " \\in %0", app.Args[0]), app.Result, vm.tp_bool) { Category = NodeCategory.MethodologyProperty });
- refs.Add(app.Args[0]);
- }
- Category = NodeCategory.MethodologyProperty;
- }
-
- public override IEnumerable<Model.Element> References
- {
- get
- {
- return refs;
- }
- }
-
- public bool IsEmpty { get { return children.Count == 0; } }
- }
-
-
- class FieldNode : ElementNode
- {
- public FieldNode(StateNode par, EdgeName realName, Model.Element elt, Model.Element tp)
- : base(par, realName, elt, tp)
- {
- }
- }
-
- class MapletNode : ElementNode
- {
- public MapletNode(StateNode par, EdgeName realName, Model.Element elt, Model.Element tp)
- : base(par, realName, elt, tp)
- {
- }
- }
-
- class VariableNode : ElementNode
- {
- public bool updatedHere;
- public string realName;
-
- public VariableNode(StateNode par, string realName, Model.Element elt, Model.Element tp)
- : base(par, new EdgeName(realName), elt, tp)
- {
- this.realName = realName;
- }
-
- public override string ShortName
- {
- set { this.name = new EdgeName(value); }
- get { return this.name.ToString(); }
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Microsoft.Boogie.ModelViewer.Vcc
+{
+ public class Provider : ILanguageProvider
+ {
+ public static Provider Instance = new Provider();
+ private Provider() { }
+
+ public bool IsMyModel(Model m)
+ {
+ return m.TryGetFunc("$is_ghost_field") != null && m.TryGetFunc("$fk_vol_version") != null;
+ }
+
+ public ILanguageSpecificModel GetLanguageSpecificModel(Model m, ViewOptions opts)
+ {
+ var vm = new VccModel(m, opts);
+ return vm;
+ }
+ }
+
+ enum DataKind
+ {
+ Flat,
+ PhysPtr,
+ SpecPtr,
+ Object,
+ Ptrset,
+ Map
+ }
+
+ class VccModel : LanguageModel
+ {
+ public readonly Model.Func f_ptr_to, f_phys_ptr_cast, f_spec_ptr_cast, f_mathint, f_local_value_is, f_spec_ptr_to, f_heap, f_select_field,
+ f_select_value, f_field, f_field_type, f_int_to_ptr, f_ptr_to_int, f_ptr, f_map_t, f_select_ptr,
+ f_owners, f_closed, f_roots, f_timestamps, f_select_bool, f_select_int, f_is_null, f_good_state,
+ f_int_to_version, f_int_to_ptrset, f_set_in0, f_is_ghost_field, f_is_phys_field, f_idx,
+ f_is_sequential_field, f_is_volatile_field, f_type_project_0, f_array, f_active_option, f_int_to_field,
+ f_blob_type, f_array_emb, f_addr, f_address_root, f_base, f_field_arr_size, f_field_arr_root, f_field_arr_index,
+ f_dot, f_prim_emb;
+ public readonly Model.Element tp_object, tp_mathint, tp_bool, tp_state, tp_ptrset, tp_heaptp;
+ public readonly Model.Element elt_me, elt_null;
+ Dictionary<Model.Element, string> typeName = new Dictionary<Model.Element, string>();
+ Dictionary<Model.Element, string> literalName = new Dictionary<Model.Element, string>();
+ Dictionary<Model.Element, Model.Element> guessedType = new Dictionary<Model.Element,Model.Element>();
+ public List<StateNode> states = new List<StateNode>();
+ public Dictionary<string, string> localVariableNames = new Dictionary<string, string>();
+
+ Dictionary<Model.Element, string> datatypeLongName = new Dictionary<Model.Element, string>();
+
+ Dictionary<int, string> fileNameMapping = new Dictionary<int, string>();
+
+ public const string selfMarker = "\\self";
+ public const int maxDatatypeNameLength = 5;
+
+ public VccModel(Model m, ViewOptions opts)
+ : base(m, opts)
+ {
+ f_ptr_to = m.MkFunc("$ptr_to", 1);
+ f_spec_ptr_to = m.MkFunc("$spec_ptr_to", 1);
+ f_phys_ptr_cast = m.MkFunc("$phys_ptr_cast", 2);
+ f_spec_ptr_cast = m.MkFunc("$spec_ptr_cast", 2);
+ f_mathint = m.MkFunc("^^mathint", 0);
+ f_local_value_is = m.MkFunc("$local_value_is", 5);
+ f_heap = m.MkFunc("$heap", 1);
+ f_select_field = m.MkFunc("Select_[$field][$ptr]$int", 2);
+ f_select_value = m.MkFunc("Select_[$ptr]$int", 2);
+ f_select_ptr = m.MkFunc("Select_[$ptr]$ptr", 2);
+ f_select_int = m.MkFunc("Select_[$ptr]$int", 2);
+ f_select_bool = m.MkFunc("Select_[$ptr]$bool", 2);
+ f_owners = m.MkFunc("$f_owner", 1);
+ f_closed = m.MkFunc("$f_closed", 1);
+ f_roots = m.MkFunc("$roots", 1);
+ f_timestamps = m.MkFunc("$f_timestamp", 1);
+ f_active_option = m.MkFunc("$f_active_option", 1);
+ f_field = m.MkFunc("$field", 1);
+ f_field_type = m.MkFunc("$field_type", 1);
+ f_int_to_ptr = m.MkFunc("$int_to_ptr", 1);
+ f_ptr_to_int = m.MkFunc("$ptr_to_int", 1);
+ f_ptr = m.MkFunc("$ptr", 2);
+ f_dot = m.MkFunc("$dot", 2);
+ f_map_t = m.MkFunc("$map_t", 2);
+ f_is_null = m.MkFunc("$is_null", 1);
+ f_good_state = m.MkFunc("$good_state", 1);
+ f_int_to_version = m.MkFunc("$int_to_version", 1);
+ f_int_to_ptrset = m.MkFunc("$int_to_ptrset", 1);
+ f_int_to_field = m.MkFunc("$int_to_field", 1);
+ f_set_in0 = m.MkFunc("$set_in0", 2);
+ f_is_ghost_field = m.MkFunc("$is_ghost_field", 1);
+ f_is_phys_field = m.MkFunc("$is_phys_field", 1);
+ f_idx = m.MkFunc("$idx", 2);
+ f_is_sequential_field = m.MkFunc("$is_sequential_field", 1);
+ f_is_volatile_field = m.MkFunc("$is_volatile_field", 1);
+ f_type_project_0 = m.MkFunc("$type_project_0", 1);
+ f_array = m.MkFunc("$array", 2);
+ f_blob_type = m.MkFunc("$blob_type", 1);
+ f_array_emb = m.MkFunc("$array_emb", 2);
+ f_addr = m.MkFunc("$addr", 1);
+ f_base = m.MkFunc("$base", 1);
+ f_prim_emb = m.MkFunc("$prim_emb", 1);
+ f_address_root = m.MkFunc("$address_root", 2);
+ f_field_arr_index = m.MkFunc("$field_arr_index", 1);
+ f_field_arr_size = m.MkFunc("$field_arr_size", 1);
+ f_field_arr_root = m.MkFunc("$field_arr_root", 1);
+
+ tp_bool = m.GetFunc("^^bool").GetConstant();
+ tp_mathint = m.GetFunc("^^mathint").GetConstant();
+ tp_object = m.GetFunc("^^object").GetConstant();
+ tp_state = m.GetFunc("^$#state_t").GetConstant();
+ tp_ptrset = m.GetFunc("^$#ptrset").GetConstant();
+
+ tp_heaptp = m.MkFunc("$heap_type", 0).GetConstant();
+
+ elt_me = m.GetFunc("$me").GetConstant();
+ elt_null = m.GetFunc("$null").GetConstant();
+
+ literalName[elt_me] = "\\me";
+ literalName[elt_null] = "NULL";
+ foreach (var tpl in f_phys_ptr_cast.Apps) {
+ if (tpl.Args[0] == elt_null)
+ literalName[tpl.Result] = "(" + TypeName(tpl.Args[1]) + "*)NULL";
+ }
+ foreach (var tpl in f_spec_ptr_cast.Apps) {
+ if (tpl.Args[0] == elt_null)
+ literalName[tpl.Result] = "(" + TypeName(tpl.Args[1]) + "^)NULL";
+ }
+ foreach (var fn in model.Functions) {
+ if (fn.Arity == 0 && fn.Name.StartsWith("l#"))
+ literalName[fn.GetConstant()] = ":" + fn.Name.Substring(2);
+ }
+
+ DecodeFileNames();
+ ComputeLocalVariableNames();
+
+ foreach (var s in m.States) {
+ var sn = new StateNode(this, s);
+ sn.SetupVars();
+ states.Add(sn);
+ }
+
+ var allStates = states.ToArray();
+ if (allStates.Length == 1 && allStates[0].vars.Count == 0) {
+ throw new Exception("This VCC model doesn't contain any variables. Was it saved with the -bvd option?");
+ }
+ states.Clear();
+ var i = 0;
+ while (i < allStates.Length) {
+ var lastGoodName = allStates[i].State.Name;
+
+ var userVars = new HashSet<string>(allStates[i].State.Variables.Where(localVariableNames.ContainsKey));
+ i++;
+ while (i < allStates.Length) {
+ foreach (var v in allStates[i].State.Variables) {
+ if (v == "$s" || userVars.Contains(v)) goto stop;
+ if (localVariableNames.ContainsKey(v))
+ userVars.Add(v);
+ }
+
+ var curName = TryParseSourceLocation(allStates[i].State.Name);
+ if (!IsBadName(curName))
+ lastGoodName = allStates[i].State.Name;
+ i++;
+ }
+
+ stop:
+
+ var lastState = allStates[i - 1];
+ lastState.capturedStateName = lastGoodName;
+ lastState.index = states.Count;
+ states.Add(lastState);
+ lastState.SetupVars();
+ }
+
+ foreach (var s in states) {
+ var elt = s.State.TryGet("$s");
+ if (elt != null)
+ literalName[elt] = "\\state'" + s.index;
+ }
+
+ GenerateSourceLocations(states);
+ }
+
+
+ bool IsBadName(SourceLocation l)
+ {
+ return l == null || l.Filename.StartsWith("<");
+ }
+
+ private void ComputeLocalVariableNames()
+ {
+ var vars = model.States.SelectMany(s => s.Variables).Where(v => v != null).Distinct();
+ Func<string, string> simpleName = s => { string dummy; return GetUserVariableNameCore(s, out dummy); };
+ var userVars = vars.Where(s => simpleName(s) != null);
+ var conflictsName = Conflicts(userVars, simpleName).ToArray();
+ Func<string, string> qName = s => { string kind, n = GetUserVariableNameCore(s, out kind); return n + " (" + kind + ")"; };
+ var conflictsKind = Conflicts(conflictsName, qName).ToArray();
+
+ var conflictsNameH = new HashSet<string>(conflictsName);
+ var conflictsKindH = new HashSet<string>(conflictsKind);
+
+ foreach (var v in userVars) {
+ if (conflictsKindH.Contains(v)) continue;
+ if (conflictsNameH.Contains(v))
+ localVariableNames[v] = qName(v);
+ else
+ localVariableNames[v] = simpleName(v);
+ }
+
+ var idx = 0;
+ foreach (var v in conflictsKind) {
+ localVariableNames[v] = string.Format("{0} #{1}", qName(v), idx++);
+ }
+ }
+
+ static IEnumerable<A> Conflicts<A, B>(IEnumerable<A> input, Func<A, B> f)
+ {
+ var revMap = new Dictionary<B, A>();
+ var reported = new HashSet<A>();
+
+ foreach (var k in input) {
+ if (reported.Contains(k)) continue;
+ var v = f(k);
+ A tmp;
+ if (revMap.TryGetValue(v, out tmp) && !tmp.Equals(k)) {
+ if (!reported.Contains(tmp)) {
+ yield return tmp;
+ reported.Add(tmp);
+ }
+ yield return k;
+ reported.Add(k);
+ } else {
+ revMap[v] = k;
+ }
+ }
+ }
+
+ #region Function name scoring
+ static string[][] prefixes = new string[][] {
+ new string[] { "F#", "$eq.$map", "Q#", },
+ new string[] { "F#lambda", },
+ new string[] { "$int_to_", "lambda@", "distinct-aux-f", "Select_","Store_", "$select.", "$store.", },
+ };
+
+ static string[][] totals = new string[][] {
+ new string[] {
+ "$current_timestamp",
+ "$full_stop", "$function_entry", "$ptr_to_i4",
+ "$ptr_to_i8", "$ptr_to_u4", "$ptr_to_u8",
+ "$span", "$sizeof", "$in_domain",
+ "$inv2",
+ "$is_claimable",
+ "$set_cardinality", "$set_difference", "$set_union",
+ "$thread_local", "$unchecked", "$writes_at",
+ "$array_range", "$arrays_disjoint",
+ "$byte_ptr_subtraction",
+ },
+
+ new string[] {
+ "$addr", "$dot", "$emb0", "$fetch_from_domain", "$in_range_phys_ptr",
+ "$in_range_spec_ptr", "$is_sequential_field", "$is_volatile_field",
+ "$is_ghost_field", "$is_phys_field", "$is_math_type", "$invok_state",
+ "$is_primitive",
+ "$spec_ptr_cast",
+ "$phys_ptr_cast",
+ "$is_null",
+ "$in_domain_lab",
+ "$inv_lab",
+ "$set_in0",
+ },
+
+ new string[] {
+ "$_pow2", "$as_composite_field", "$as_field_with_type", "$as_in_range_t",
+ "$as_primitive_field", "$base", "$call_transition", "tickleBool", "Ctor",
+ "$mv_state", "$field", "$field_arr_root", "$field_kind", "$field_offset",
+ "$field_parent_type", "$field_type", "$file_name_is", "$good_state",
+ "$good_state_ext", "$function_arg_type", "$has_field_at0", "$map_domain",
+ "$map_range", "$map_t", "$ptr_to", "$ptr_to_i1", "$ptr_to_i2",
+ "$ptr_to_u1", "$ptr_to_u2", "$is_unwrapped", "$is_unwrapped_dynamic",
+ "$heap", "$closed", "$owner", "$owns", "$modifies", "$post_unwrap",
+ "$pow2", "$pre_unwrap", "$ptr", "$is", "$in_range_t", "$roots",
+ "$timestamp", "$type_branch", "$type_code_is", "$type_project_0",
+ "$typemap", "$set_in_pos", "$updated_owns", "$ver_domain", "$vs_state",
+ "$set_singleton",
+ "$f_owner", "$f_closed", "$f_timestamps",
+ "$local_value_is",
+ "$field_arr_ctor",
+ "$idx",
+ },
+ };
+
+ string[] state_props = new string[] { };
+
+ Dictionary<string, int> functionScores = new Dictionary<string, int>();
+
+ int FunctionScore(string name)
+ {
+ if (functionScores.Count == 0) {
+ for (int i = 0; i < totals.Length; ++i)
+ foreach (var s in totals[i])
+ functionScores[s] = i;
+ }
+
+ int res;
+ if (functionScores.TryGetValue(name, out res))
+ return res;
+
+ res = -1;
+ if (name[0] == '$' && name.EndsWith("_to_int"))
+ res = 1;
+ else if (name.EndsWith("#frame"))
+ res = 2;
+ else if (name.Contains("#limited#"))
+ res = 2;
+ else {
+ for (int i = 0; i < prefixes.Length; ++i)
+ foreach (var p in prefixes[i])
+ if (name.StartsWith(p)) {
+ res = i;
+ //goto stop;
+ }
+ //stop: ;
+ }
+
+ if (res == -1)
+ res = 1; // default
+
+ functionScores[name] = res;
+ return res;
+ }
+ #endregion
+
+ private void DecodeFileNames()
+ {
+ var fis = model.GetFunc("$file_name_is");
+ foreach (var f in model.Functions) {
+ if (f.Arity == 0 && f.Name.StartsWith("#file^")) {
+ var sb = new StringBuilder();
+ var idx = 6;
+ var name = f.Name;
+ while (idx < name.Length) {
+ if (name[idx] == '?') {
+ var c = (char)Int32.Parse(name.Substring(idx + 1, 2), System.Globalization.NumberStyles.HexNumber);
+ sb.Append(c);
+ idx += 3;
+ } else {
+ sb.Append(name[idx++]);
+ }
+ }
+ name = sb.ToString();
+
+ foreach (var app in fis.AppsWithArg(1, f.GetConstant()))
+ fileNameMapping[app.Args[0].AsInt()] = name;
+ }
+ }
+ }
+
+ private Model.Element DecodeDT(string dt)
+ {
+ if (dt.StartsWith("dt")) {
+ var tpName = dt.Replace("dt", "#distTp");
+ var f = model.TryGetFunc(tpName);
+ if (f != null) {
+ return f.GetConstant();
+ //var res = f_type_project_0.TryEval(ptr);
+ //if (res != null)
+ // tp = res;
+ }
+ }
+ return null;
+ }
+
+ private string DecodeToken(string name, ref Model.Element tp)
+ {
+ var idx = name.LastIndexOf("$");
+ if (idx < 0) return null;
+ var words = name.Substring(idx + 1).Split('.', '^', '!', '#', '@');
+ if (words.Length > 3)
+ tp = DecodeDT(words[3]);
+ return string.Format("{0}({1},{2})", fileNameMapping[int.Parse(words[0])], words[1], words[2]);
+ }
+
+ public string GetUserVariableName(string name)
+ {
+ string res;
+ localVariableNames.TryGetValue(name, out res);
+ return res;
+ }
+
+
+ string GetUserVariableNameCore(string name, out string kind)
+ {
+ if (name.StartsWith("L#")) {
+ kind = "local";
+ return name.Substring(2);
+ }
+
+ if (name.StartsWith("P#")) {
+ kind = "in-param";
+ return name.Substring(2);
+ }
+
+ if (name.StartsWith("OP#")) {
+ kind = "out-param";
+ return name.Substring(3);
+ }
+
+ if (name.StartsWith("SL#")) {
+ kind = "spec local";
+ return name.Substring(3);
+ }
+
+ if (name.StartsWith("SP#")) {
+ kind = "spec in-param";
+ return name.Substring(3);
+ }
+
+ if (name.StartsWith("local.")) {
+ kind = "param copied to local";
+ return name.Substring(6);
+ }
+
+ if (name.StartsWith("addr.")) {
+ kind = "stack-allocated struct";
+ return name.Substring(5);
+ }
+
+ if (name == "$result") {
+ kind = "function return value";
+ return "\\result";
+ }
+
+ if (name.StartsWith("res__") && viewOpts.ViewLevel >= 1) {
+ kind = "call result";
+ return name;
+ }
+
+ if (name == "$s" && viewOpts.ViewLevel >= 1) {
+ kind = "current state";
+ return "\\now";
+ }
+
+ kind = null;
+ return null;
+ }
+
+
+ private string LiteralName(Model.Element elt)
+ {
+ string r;
+
+ if (literalName.TryGetValue(elt, out r))
+ return r;
+
+ r = TryTypeName(elt);
+ if (r != null) {
+ literalName[elt] = r;
+ return r;
+ }
+
+ var i = elt as Model.Integer;
+ if (i != null)
+ return AsPow2(i);
+
+ var bv = elt as Model.BitVector;
+ if (bv != null)
+ return bv.Numeral + "bv" + bv.Size.ToString();
+
+ return null;
+ }
+
+ public Model.Element LocalType(string localName)
+ {
+ string dummy;
+ var v = GetUserVariableNameCore(localName, out dummy);
+ if (v == null) v = localName;
+ var c = model.TryGetFunc("#loc." + v);
+ if (c != null) {
+ var localIs = f_local_value_is.AppWithArg(2, c.GetConstant());
+ if (localIs != null)
+ return localIs.Args[4];
+ }
+ foreach (var s in model.States.Reverse()) {
+ var val = s.TryGet(localName);
+ var tp = GuessType(val);
+ if (tp != tp_mathint)
+ return tp;
+ }
+ return tp_mathint;
+ }
+
+ public Model.Element Image(Model.Element elt, Model.Func f)
+ {
+ var r = f.AppWithResult(elt);
+ if (r != null)
+ return r.Args[0];
+ return null;
+ }
+
+ string TypeNameCore(Model.Element elt)
+ {
+ var deref = Image(elt, f_ptr_to);
+ if (deref != null)
+ return TypeName(deref) + "*";
+ deref = Image(elt, f_spec_ptr_to);
+ if (deref != null)
+ return TypeName(deref) + "^";
+ deref = Image(elt, f_blob_type);
+ if (deref != null)
+ return "_(blob " + CanonicalName(deref) + ")";
+ var mapt = f_map_t.AppWithResult(elt);
+ if (mapt != null)
+ return string.Format("{1}[{0}]", TypeName(mapt.Args[0]), TypeName(mapt.Args[1]));
+
+ var arr = f_array.AppWithResult(elt);
+ if (arr != null) {
+ return string.Format("{0}[{1}]", TypeName(arr.Args[0]), arr.Args[1].ToString());
+ }
+
+ foreach (var app in elt.Names)
+ if (app.Func.Arity == 0 && app.Func.Name.StartsWith("^")) {
+ var n = app.Func.Name.Substring(1);
+ switch (n) {
+ case "^i1": return "int8_t";
+ case "^u1": return "uint8_t";
+ case "^i2": return "int16_t";
+ case "^u2": return "uint16_t";
+ case "^i4": return "int32_t";
+ case "^u4": return "uint32_t";
+ case "^i8": return "int64_t";
+ case "^u8": return "uint64_t";
+ case "^bool": return "bool";
+ default:
+ var pref = "_vcc_math_type_";
+ if (n.StartsWith(pref)) n = n.Substring(pref.Length);
+ return n;
+ }
+ }
+
+ return null;
+ }
+
+ public string TypeName(Model.Element elt)
+ {
+ var r = TryTypeName(elt);
+ if (r == null)
+ return elt.ToString();
+ else return r;
+ }
+
+ public string TryTypeName(Model.Element elt)
+ {
+ string res;
+ if (!typeName.TryGetValue(elt, out res)) {
+ typeName[elt] = elt.ToString(); // avoid infinite recursion
+ res = TypeNameCore(elt);
+ typeName[elt] = res;
+ }
+ return res;
+ }
+
+ public static readonly string[] synthethic_fields = new string[] { "$f_owns", "$f_ref_cnt", "$f_vol_version", "$f_root", "$f_group_root", "$f_active_option" };
+
+ public string ConstantFieldName(Model.Element elt)
+ {
+ string res;
+ IsConstantField(elt, out res);
+ return res;
+ }
+
+ public bool IsConstantField(Model.Element elt)
+ {
+ string dummy;
+ return IsConstantField(elt, out dummy);
+ }
+
+ public bool IsConstantField(Model.Element elt, out string theName)
+ {
+ var bestScore = int.MinValue;
+ string bestName = null;
+
+ foreach (var t in elt.Names) {
+ var score = int.MinValue;
+ string name = null;
+ if (t.Args.Length == 0) {
+ name = t.Func.Name;
+ score = 0;
+ var dotIdx = name.IndexOf('.');
+ if (dotIdx > 0) {
+ score += 10;
+ name = name.Substring(dotIdx + 1);
+ }
+ if (name.Contains('#')) score -= 1;
+ } else if (t.Func.Name.StartsWith("$f_") && synthethic_fields.Contains(t.Func.Name)) {
+ name = string.Format("{0}<{1}>", t.Func.Name.Substring(3).Replace("root", "alloc_root"), TypeName(t.Args[0]));
+ score = 6;
+ } else if (t.Func == f_array_emb) {
+ name = string.Format("[0] (of {0}[{1}])", TypeName(t.Args[0]), t.Args[1].ToString());
+ score = 5;
+ }
+ if (score > bestScore) {
+ bestScore = score;
+ bestName = name;
+ }
+ }
+
+ theName = bestName;
+ return bestScore >= 5;
+ }
+
+ bool IsSomeState(Model.Element elt)
+ {
+ var tp = GuessType(elt);
+ return tp == tp_state || tp == tp_heaptp;
+ }
+
+ bool IsThisState(Model.Element st, Model.Element elt)
+ {
+ return elt == st || elt == f_heap.TryEval(st);
+ }
+
+ Model.Element GuessType(Model.Element element)
+ {
+ Model.Element res;
+ if (!guessedType.TryGetValue(element, out res)) {
+ res = GuessTypeCore(element);
+ guessedType[element] = res;
+ }
+ return res;
+ }
+
+ Model.Element GuessTypeCore(Model.Element element)
+ {
+ if (element is Model.Boolean)
+ return tp_bool;
+
+ var fld = f_field.TryEval(element);
+ if (fld != null) {
+ var tp = f_field_type.TryEval(fld);
+ if (tp != null) {
+ var ptp = f_ptr_to.TryEval(tp);
+ if (ptp != null)
+ return ptp;
+ ptp = f_spec_ptr_to.TryEval(tp);
+ if (ptp != null)
+ return ptp;
+ }
+ return tp_object;
+ }
+
+ foreach (var tpl in element.References) {
+ if (element == tpl.Result) {
+ if (tpl.Func == f_ptr)
+ return tp_object;
+ if (tpl.Func == f_heap)
+ return tp_heaptp;
+ }
+
+ if (tpl.Args.Length >= 1 && tpl.Args[0] == element) {
+ if (tpl.Func == f_heap || tpl.Func == f_closed || tpl.Func == f_good_state)
+ return tp_state;
+ }
+
+ if (tpl.Func == f_select_bool)
+ if (tpl.Args[0] == element)
+ return tp_ptrset;
+ else if (tpl.Args[1] == element)
+ return tp_object;
+
+ var fname = tpl.Func.Name;
+
+ if (tpl.Args.Length == 2 && tpl.Args[0] == element && fname.StartsWith("$select.$map_t")) {
+ var mt = model.TryGetFunc("MT#" + fname);
+ if (mt != null && mt.Arity == 0)
+ return mt.GetConstant();
+ var t1 = GuessType(tpl.Args[1]);
+ var t2 = GuessType(tpl.Result);
+ var t = f_map_t.TryEval(t1, t2);
+ if (t != null)
+ return t;
+ }
+
+ var tpName = DataTypeName(element, tpl);
+ if (tpName != null) {
+ var tp = model.TryGetFunc("^$#" + tpName);
+ if (tp != null)
+ return tp.GetConstant();
+ }
+ }
+
+ return tp_mathint;
+ }
+
+ string DataTypeName(Model.Element elt, Model.FuncTuple tpl)
+ {
+ var fname = tpl.Func.Name;
+ if (tpl.Args.Length == 1 && tpl.Args[0] == elt && fname.StartsWith("RF#")) {
+ var fldName = tpl.Func.Name.Substring(3);
+ var idx = fldName.LastIndexOf('.');
+ if (idx > 0) {
+ return fldName.Substring(0, idx).Replace("_vcc_math_type_", "");
+ }
+ }
+
+ if (tpl.Args.Length == 1 && tpl.Args[0] == elt && (fname.StartsWith("DSZ#") || fname.StartsWith("RSZ#") || fname.StartsWith("DGH#"))) {
+ return fname.Substring(4).Replace("_vcc_math_type_", "");
+ }
+ return null;
+ }
+
+ public DataKind GetKind(Model.Element tp, out Model.FuncTuple tpl)
+ {
+ tpl = null;
+
+ if (tp == tp_object)
+ return DataKind.Object;
+ else if (tp == tp_ptrset)
+ return DataKind.Ptrset;
+
+ tpl = f_ptr_to.AppWithResult(tp);
+ if (tpl != null) return DataKind.PhysPtr;
+ tpl = f_spec_ptr_to.AppWithResult(tp);
+ if (tpl != null) return DataKind.SpecPtr;
+ tpl = f_map_t.AppWithResult(tp);
+ if (tpl != null) return DataKind.Map;
+
+ return DataKind.Flat;
+ }
+
+ public DataKind GetKind(Model.Element tp)
+ {
+ Model.FuncTuple dummy;
+ return GetKind(tp, out dummy);
+ }
+
+
+ public Model.Element WrapForUse(Model.Element elt, Model.Element tp)
+ {
+ Model.FuncTuple tpl;
+ var kind = GetKind(tp, out tpl);
+
+ if (kind == DataKind.Flat) {
+ if (elt.Kind == Model.ElementKind.Integer) {
+ var tpname = TypeName(tp);
+ if(tpname.StartsWith("$")) tpname = tpname.Substring(1);
+ if (tpname.StartsWith("#")) {
+ foreach (var tupl in elt.References) {
+ if (tupl.Args.Length == 1 && tupl.Args[0] == elt && tupl.Func.Name.StartsWith("$int_to_") && tupl.Func.Name.EndsWith(tpname)) {
+ return tupl.Result;
+ }
+ }
+ }
+ }
+ return elt;
+ }
+
+ if (kind == DataKind.Map) {
+ if (elt.Kind == Model.ElementKind.Integer) {
+ Model.Element theMap = null;
+ foreach (var conv in model.Functions)
+ // really, we should reconstruct the name of this function, but this is painful
+ if (conv.Arity == 1 && conv.Name.StartsWith("$int_to_map_t")) {
+ var app = conv.AppWithArg(0, elt);
+ if (app != null) {
+ theMap = app.Result;
+ break;
+ }
+ }
+ if (theMap == null) return elt;
+ return theMap;
+ }
+ return elt;
+ } else if (kind == DataKind.Ptrset) {
+ var tmp = f_int_to_ptrset.TryEval(elt);
+ if (tmp != null)
+ return tmp;
+ return elt;
+ }
+
+ if (kind == DataKind.PhysPtr || kind == DataKind.SpecPtr || kind == DataKind.Object) {
+ if (elt.Kind == Model.ElementKind.Integer) {
+ var tmp = f_int_to_ptr.TryEval(elt);
+ if (tmp != null)
+ elt = tmp;
+ }
+ }
+
+ if (kind == DataKind.Object)
+ return elt;
+
+ if (kind == DataKind.PhysPtr)
+ return Util.OrElse(f_phys_ptr_cast.TryEval(elt, tpl.Args[0]), elt);
+
+ if (kind == DataKind.SpecPtr)
+ return Util.OrElse(f_spec_ptr_cast.TryEval(elt, tpl.Args[0]), elt);
+
+ Util.Assert(false);
+ return elt;
+ }
+
+ void AddSpecialField(StateNode state, Model.Element elt, List<ElementNode> res, string name, Model.Func select_map)
+ {
+ if (elt == null) return;
+
+ var map = state.State.TryGet("$s");
+ if (map != null)
+ map = select_map.TryEval(map);
+ if (map != null) {
+ var model = elt.Model;
+ Model.Element val = f_select_bool.TryEval(map, elt);
+ Model.Element tp = tp_bool;
+ if (val == null) {
+ val = f_select_ptr.TryEval(map, elt);
+ tp = tp_object;
+ }
+ if (val == null) {
+ val = f_select_int.TryEval(map, elt);
+ tp = tp_mathint;
+ }
+ if (val != null) {
+ res.Add(new FieldNode(state, new EdgeName(name), val, tp) { Category = NodeCategory.MethodologyProperty });
+ }
+ }
+ }
+
+ void AddPointerFunction(StateNode state, Model.Element elt, List<ElementNode> res, string name, Model.Func fn, Model.Element tp)
+ {
+ if (elt == null) return;
+
+ var val = fn.TryEval(elt);
+ if (val != null) {
+ res.Add(new FieldNode(state, new EdgeName(name), val, tp) { Category = NodeCategory.MethodologyProperty });
+ }
+ }
+
+ void AddPtrType(StateNode state, Model.Element elt, List<ElementNode> res)
+ {
+ var f = f_field.TryEval(elt);
+ if (f == null) return;
+
+ var tp = f_field_type.TryEval(f);
+
+ var seq = "";
+
+ var is_seq = f_is_sequential_field.TryEval(f) as Model.Boolean;
+ var is_vol = f_is_volatile_field.TryEval(f) as Model.Boolean;
+
+ if (is_seq != null && is_vol != null && is_seq.Value == is_vol.Value) {
+ seq = " (volatile/sequential mismatch)";
+ } else if ((is_seq != null && is_seq.Value) || (is_vol != null && !is_vol.Value)) {
+ seq = " (sequential)";
+ } else if ((is_seq != null && !is_seq.Value) || (is_vol != null && is_vol.Value)) {
+ seq = " (volatile)";
+ }
+
+ if (tp != null || seq != "") {
+ res.Add(new FieldNode(state, new EdgeName("\\typeof" + seq), tp, tp_mathint) { Category = NodeCategory.MethodologyProperty });
+ }
+ }
+
+ string SkolemName(Model.Func f, ref Model.Element tp)
+ {
+ if (f.Name.IndexOf('!') > 0) {
+ var tok = DecodeToken(f.Name, ref tp);
+ if (tok != null) {
+ var baseName = f.Name.Substring(0, f.Name.LastIndexOf('$'));
+ if (baseName.StartsWith("Q#"))
+ baseName = baseName.Substring(2);
+ return string.Format("{0}@{1}", baseName, ShortenToken(tok, 10, false));
+ }
+ }
+ return null;
+ }
+
+ string GlobalName(Model.Func f, ref Model.Element tp)
+ {
+ if (f.Name.StartsWith("G#")) {
+ var idx = f.Name.LastIndexOf("#dt");
+ if (idx < 0) return null;
+ var name = f.Name.Substring(2, idx - 2);
+ tp = DecodeDT(f.Name.Substring(idx + 1));
+ return string.Format("::{0}", name);
+ }
+ return null;
+ }
+
+
+ public IEnumerable<ElementNode> CommonNodes(StateNode state)
+ {
+ var skolems = new List<ElementNode>();
+
+ Model.Element tp = null;
+
+ foreach (var f in model.Functions) {
+ if (f.Arity != 0) continue;
+ var s = SkolemName(f, ref tp);
+ if (s == null)
+ s = GlobalName(f, ref tp);
+ if (s != null) {
+ if (tp == null)
+ tp = GuessType(f.GetConstant());
+ var val = WrapForUse(f.GetConstant(), tp);
+ skolems.Add(new VariableNode(state, s, val, tp));
+ }
+ }
+
+ return skolems;
+ }
+
+ private Model.Element GuessPtrTo(Model.Element tp)
+ {
+ var p = f_ptr_to.TryEval(tp);
+ if (p != null) return p;
+ p = f_spec_ptr_to.TryEval(tp);
+ if (p != null) return p;
+ var nm = model.MkFunc("*ptrto_" + TypeName(tp), 0).GetConstant();
+ f_ptr_to.AddApp(nm, tp);
+ return f_ptr_to.TryEval(tp);
+ }
+
+ private Model.Element PtrTo(Model.Element tp, Model.Func f_ptr_to)
+ {
+ var p = f_ptr_to.TryEval(tp);
+ if (p != null) return p;
+ var nm = model.MkFunc("*" + f_ptr_to.Name + "_" + TypeName(tp), 0).GetConstant();
+ f_ptr_to.AddApp(nm, tp);
+ return f_ptr_to.TryEval(tp);
+ }
+
+ private bool IsArrayField(Model.Element ptr)
+ {
+ return ptr != null && f_idx.TryEval(ptr, model.TryMkElement("0")) != null;
+ }
+
+ public IEnumerable<ElementNode> GetExpansion(StateNode state, Model.Element elt, Model.Element tp)
+ {
+ List<ElementNode> result = new List<ElementNode>();
+ Model.FuncTuple tpl;
+
+ if (elt == null) return result;
+
+ var kind = GetKind(tp, out tpl);
+ if (kind == DataKind.PhysPtr || kind == DataKind.SpecPtr || kind == DataKind.Object) {
+ var heap = state.State.TryGet("$s");
+ if (heap != null)
+ heap = f_heap.TryEval(heap);
+ var addresses = new HashSet<Model.Element>();
+
+ if (heap != null) {
+ var basePtr = f_base.TryEval(elt);
+ foreach (var fld in f_select_field.AppsWithArg(0, heap)) {
+ var val = f_select_value.TryEval(fld.Result, elt);
+ if (val != null) {
+ var field = fld.Args[1];
+ if (!IsConstantField(field) && viewOpts.ViewLevel <= 2)
+ continue;
+ var addr = f_dot.TryEval(elt, field);
+ if (addr != null) addresses.Add(addr);
+ var node = ComputeUnionActiveOption(state, elt, val, field);
+ if (node != null)
+ result.Add(node);
+ else
+ BuildFieldNode(result, state, addr, field, val, addr);
+ }
+ }
+ //result.Sort(CompareFields);
+ }
+
+ {
+ foreach (var app in f_idx.AppsWithArg(0, elt)) {
+ var addr = app.Result;
+ Model.Element val = null, atp = tp;
+
+ addresses.Add(addr);
+
+ foreach (var papp in f_dot.AppsWithResult(addr)) {
+ var tmp = f_select_value.OptEval(f_select_field.OptEval(heap, papp.Args[1]), papp.Args[0]);
+ if (tmp != null) {
+ val = tmp;
+ var tt = f_field_type.TryEval(papp.Args[1]);
+ if (tt != null) atp = tt;
+ }
+ }
+
+ if (val != null)
+ val = WrapForUse(val, atp);
+ result.Add(new MapletNode(state, new EdgeName(this, "[%0]", app.Args[1]), val, atp) { Category = NodeCategory.Maplet });
+ if (addr != null)
+ result.Add(new MapletNode(state, new EdgeName(this, "&[%0]", app.Args[1]), addr, GuessPtrTo(atp)) { Category = NodeCategory.Maplet });
+ }
+ }
+
+ foreach (var ptr in f_dot.AppsWithArg(0, elt)) {
+ if (addresses.Contains(ptr.Result)) continue;
+ var fld = ptr.Args[1];
+ var idx = f_field_arr_index.TryEval(fld);
+ if (idx != null) {
+ var xtp = f_field_type.TryEval(fld);
+ result.Add(new MapletNode(state, new EdgeName(this, "&[%0] of %1", idx, f_field_arr_size.TryEval(fld)), ptr.Result, GuessPtrTo(xtp)) { Category = NodeCategory.Maplet });
+ }
+ if (!IsConstantField(ptr.Args[1])) continue;
+ BuildFieldNode(result, state, ptr.Result, ptr.Args[1], null, ptr.Result);
+ }
+
+ AddSpecialField(state, elt, result, "\\closed", f_closed);
+ AddSpecialField(state, elt, result, "\\owner", f_owners);
+ AddSpecialField(state, elt, result, "\\root", f_roots);
+ AddSpecialField(state, elt, result, "\\timestamp", f_timestamps);
+ AddPointerFunction(state, elt, result, "\\embedding", f_prim_emb, tp_object);
+ AddPointerFunction(state, elt, result, "\\addr", f_addr, tp_mathint);
+
+ if (viewOpts.ViewLevel >= 1) {
+ AddPtrType(state, elt, result);
+ AddCasts(state, elt, result);
+ var sets = new SetsNode(state, elt);
+ if (!sets.IsEmpty)
+ result.Add(sets);
+ }
+
+ } else if (kind == DataKind.Map) {
+ var elTp = tpl.Args[1];
+ foreach (var sel in model.Functions)
+ if (sel.Arity == 2 && sel.Name.StartsWith("$select.$map_t")) {
+ foreach (var app in sel.AppsWithArg(0, elt)) {
+ var val = WrapForUse(app.Result, elTp);
+ var edgname = new EdgeName(this, "[%0]", app.Args[1]);
+ result.Add(new MapletNode(state, edgname, val, elTp) { Category = NodeCategory.Maplet });
+ }
+ }
+ } else if (kind == DataKind.Ptrset) {
+ foreach (var sel in f_select_bool.AppsWithArg(0, elt)) {
+ var edgname = new EdgeName(this, "[%0]", sel.Args[1]);
+ result.Add(new MapletNode(state, edgname, sel.Result, tp_bool) { Category = NodeCategory.Maplet });
+ }
+ } else if (kind == DataKind.Flat) {
+ foreach (var tupl in elt.References) {
+ if (tupl.Args.Length == 1 && tupl.Args[0] == elt) {
+ var fname = tupl.Func.Name;
+ var idx = fname.LastIndexOf('.');
+ if (fname.StartsWith("RF#") && idx > 0) {
+ fname = fname.Substring(idx + 1);
+ } else if (fname.StartsWith("DP#p")) {
+ fname = fname.Substring(4);
+ idx = fname.IndexOf('#');
+ if (idx > 0)
+ fname = fname.Substring(idx + 1) + "#" + fname.Substring(0, idx);
+ } else {
+ fname = null;
+ }
+
+ if (fname != null)
+ result.Add(new FieldNode(state, new EdgeName(fname), tupl.Result, GuessType(tupl.Result)) { Category = NodeCategory.SpecField });
+ }
+ }
+ }
+
+ if (!(elt is Model.Boolean)) {
+ var curState = state.State.TryGet("$s");
+
+ foreach (var tupl in elt.References) {
+ {
+ var seenSelf = false;
+ var seenState = false;
+ var seenThisState = false;
+ var args = tupl.Args;
+ for (int i = 0; i < args.Length; ++i) {
+ if (args[i] == elt) seenSelf = true;
+ if (IsThisState(curState, args[i])) seenThisState = true;
+ else if (IsSomeState(args[i])) seenState = true;
+ }
+ if (!seenSelf) continue; // not looking for aliases (maybe we should?)
+ if (seenState && !seenThisState) continue;
+ }
+
+ var argsFmt = new StringBuilder();
+ var name = tupl.Func.Name;
+
+ var score = FunctionScore(name);
+ if (score >= viewOpts.ViewLevel)
+ continue;
+
+ var retTp = GuessType(tupl.Result);
+ var retVal = tupl.Result;
+
+ var cat = NodeCategory.MethodologyProperty;
+ if (name.StartsWith("F#")) {
+ name = name.Substring(2);
+ cat = NodeCategory.UserFunction;
+ }
+
+ if (name.StartsWith("DF#")) {
+ name = name.Substring(3);
+ cat = NodeCategory.UserFunction;
+ }
+
+ if (name.StartsWith("$eq.$"))
+ name = "EQ";
+
+ {
+ Model.Element sktp = null;
+ var sk = SkolemName(tupl.Func, ref sktp);
+ if (sk != null) {
+ name = sk;
+ if (sktp != null)
+ retVal = WrapForUse(tupl.Result, sktp);
+ cat = NodeCategory.Maplet;
+ }
+ }
+
+ {
+ argsFmt.Append(name).Append("(");
+ var args = new List<Model.Element>();
+ foreach (var a in tupl.Args) {
+ if (IsThisState(curState, a))
+ argsFmt.Append("\\now, ");
+ else if (a == elt)
+ argsFmt.Append(selfMarker + ", ");
+ else {
+ argsFmt.AppendFormat("%{0}, ", args.Count);
+ args.Add(a);
+ }
+ }
+ argsFmt.Length -= 2;
+ argsFmt.Append(")");
+ var edgeName = new EdgeName(this, argsFmt.ToString(), args.ToArray());
+ result.Add(new MapletNode(state, edgeName, retVal, retTp) { ViewLevel = score, Category = cat });
+ }
+
+ }
+ }
+
+ return result;
+ }
+
+ private FieldNode ComputeUnionActiveOption(StateNode state, Model.Element elt, Model.Element val, Model.Element field)
+ {
+ if (f_active_option.AppsWithResult(field).FirstOrDefault() != null) {
+ var activeOpt = f_dot.OptEval(elt, f_int_to_field.OptEval(val));
+ if (activeOpt != null) {
+ var nm = ConstantFieldName(field);
+ var fieldNode = new FieldNode(state, new EdgeName(nm), activeOpt, GuessType(activeOpt)) { Category = NodeCategory.MethodologyProperty };
+ return fieldNode;
+ }
+ }
+ return null;
+ }
+
+ private void AddCasts(StateNode state, Model.Element elt, List<ElementNode> result)
+ {
+ foreach (var app in f_phys_ptr_cast.AppsWithArg(0, elt)) {
+ if (app.Result != elt)
+ result.Add(new MapletNode(state, new EdgeName(this, "(" + TypeName(app.Args[1]) + "*)..."), app.Result, PtrTo(app.Args[1], f_ptr_to)));
+ }
+ foreach (var app in f_spec_ptr_cast.AppsWithArg(0, elt)) {
+ if (app.Result != elt)
+ result.Add(new MapletNode(state, new EdgeName(this, "(" + TypeName(app.Args[1]) + "^)..."), app.Result, PtrTo(app.Args[1], f_spec_ptr_to)));
+ }
+ var addr = f_addr.TryEval(elt);
+ if (addr != null) {
+ foreach (var app in f_blob_type.Apps) {
+ var blob = f_address_root.TryEval(addr, app.Result);
+ if (blob != null) {
+ result.Add(new MapletNode(state, new EdgeName(this, TypeName(app.Result) + "..."), blob, app.Result));
+ }
+ }
+ }
+ }
+
+ private void BuildFieldNode(List<ElementNode> result, StateNode state, Model.Element ptr, Model.Element field, Model.Element val, Model.Element addr)
+ {
+ var ftp = f_field_type.TryEval(field);
+ if (val != null)
+ val = WrapForUse(val, ftp);
+
+ if (IsArrayField(ptr)) {
+ val = addr;
+ addr = null;
+ ftp = GuessPtrTo(ftp);
+ }
+
+ var nm = ConstantFieldName(field);
+ var edgname = nm == null ? field.ToString() : nm;
+
+ var cat = NodeCategory.PhysField;
+ if (f_is_ghost_field.IsTrue(field))
+ cat = NodeCategory.SpecField;
+ if (nm != null && nm.Contains("<"))
+ cat = NodeCategory.MethodologyProperty;
+
+ var fieldNode = new FieldNode(state, new EdgeName(edgname), val, ftp) { Category = cat};
+ result.Add(fieldNode);
+
+ if (addr != null) {
+ result.Add(new FieldNode(state, new EdgeName("&" + edgname), addr, GuessPtrTo(ftp)) { Category = cat });
+ }
+ }
+
+ public override IEnumerable<IState> States
+ {
+ get
+ {
+ return states;
+ }
+ }
+
+ private int DataTypeToString(StringBuilder sb, int level, Model.Element elt)
+ {
+ Model.FuncTuple ctor = null;
+ int len = 1;
+ string dataTypeType = null;
+ foreach (var app in elt.References) {
+ var n = app.Func.Name;
+ if (app.Result == elt && n.StartsWith("DF#")) {
+ ctor = app;
+ }
+ var tmp = DataTypeName(elt, app);
+ if (tmp != null) dataTypeType = tmp;
+ }
+
+ if (dataTypeType != null) {
+ if (ctor != null)
+ sb.Append(ctor.Func.Name.Substring(3));
+ else
+ sb.Append(DataTypeShortName(elt, dataTypeType));
+ if (ctor != null && ctor.Args.Length > 0) {
+ if (level <= 0) sb.Append("(...)");
+ else {
+ sb.Append("(");
+ for (int i = 0; i < ctor.Args.Length; ++i) {
+ if (i != 0) sb.Append(", ");
+ len += DataTypeToString(sb, level - 1, ctor.Args[i]);
+ }
+ sb.Append(")");
+ }
+ }
+ } else {
+ sb.Append(CanonicalName(elt));
+ }
+ return len;
+ }
+
+ private string DataTypeShortName(Model.Element elt, string tp)
+ {
+ var baseName = tp;
+
+ var hd = model.MkFunc("DGH#" + tp, 1).TryEval(elt);
+ if (hd != null) {
+ foreach (var nm in hd.References) {
+ if (nm.Func.Arity == 0 && nm.Func.Name.StartsWith("DH#"))
+ baseName = nm.Func.Name.Substring(3);
+ }
+ }
+
+ return baseName;
+ }
+
+ private string CanonicalBaseNameCore(string name, Model.Element elt, bool doDatatypes, ref NameSeqSuffix suff)
+ {
+ var vm = this;
+
+ if (name.Contains("[") || name.Contains("'"))
+ name = "";
+
+ if (name != "")
+ return name;
+
+ var isNull = false;
+ foreach (var tpl in elt.References) {
+ var fn = tpl.Func;
+ if (fn.Name.StartsWith("$select.$map_t") && fn.Arity == 2 && tpl.Args[0] == elt)
+ return "map";
+ if (fn.Name.StartsWith("$int_to_map_t") && tpl.Result == elt)
+ return "map";
+
+ if (fn.Arity >= 1 && tpl.Args[0] == elt) {
+ if (fn == f_select_bool)
+ return "ptrset";
+ }
+
+ if (tpl.Result == elt)
+ if (fn == f_int_to_version)
+ return "version";
+
+ if (fn == f_is_null && tpl.Result == model.True)
+ isNull = true;
+
+ var dtpName = DataTypeName(elt, tpl);
+ if (dtpName != null) {
+ var sb = new StringBuilder();
+ string prev = null;
+ datatypeLongName[elt] = "*SELF*"; // in case we recurse (but this shouldn't happen)
+ for (int lev = 0; lev < 10; lev++) {
+ sb.Length = 0;
+ var len = DataTypeToString(sb, lev, elt);
+ if (prev == null || len <= maxDatatypeNameLength)
+ prev = sb.ToString();
+ }
+
+ datatypeLongName[elt] = prev;
+ suff = NameSeqSuffix.WhenNonZero;
+ return prev;
+ }
+ }
+
+ var fld = vm.f_field.TryEval(elt);
+ if (fld != null) {
+ var tp = vm.f_field_type.TryEval(fld);
+ if (tp != null) {
+ var n = vm.TryTypeName(tp);
+ if (n != null) {
+ if (isNull)
+ return "(" + n + "*)NULL";
+ return n;
+ }
+ }
+ }
+
+ return "";
+ }
+
+ protected override string CanonicalBaseName(Model.Element elt, out NameSeqSuffix suff)
+ {
+ var lit = this.LiteralName(elt);
+ if (lit != null) {
+ suff = NameSeqSuffix.None;
+ return lit;
+ }
+ if (datatypeLongName.TryGetValue(elt, out lit)) {
+ suff = NameSeqSuffix.WhenNonZero;
+ return lit;
+ }
+
+ var name = base.CanonicalBaseName(elt, out suff);
+ name = CanonicalBaseNameCore(name, elt, true, ref suff);
+
+ return name;
+ }
+
+ public override string PathName(IEnumerable<IDisplayNode> path)
+ {
+ var sb = new StringBuilder();
+ foreach (var d in path) {
+ var name = d.Name;
+ if (name == "") continue; // can that happen?
+ if (name.Contains("(") && name.Contains(selfMarker)) {
+ var repl = name.Replace(selfMarker, sb.ToString());
+ sb.Length = 0;
+ sb.Append(repl);
+ } else {
+ if (sb.Length > 0 && name[0] != '[')
+ sb.Append("->");
+ sb.Append(d.Name);
+ }
+ }
+
+ return sb.ToString();
+ }
+ }
+
+ class StateNode : NamedState
+ {
+ internal VccModel vm;
+ internal List<VariableNode> vars;
+ internal List<ElementNode> commons;
+ internal int index;
+ internal string capturedStateName;
+
+ public StateNode(VccModel parent, Model.CapturedState s)
+ : base(s, parent)
+ {
+ this.capturedStateName = s.Name;
+ this.vm = parent;
+ }
+
+ internal void SetupVars()
+ {
+ if (vars != null) return;
+ vars = new List<VariableNode>();
+
+ var names = Util.Empty<string>();
+
+ if (vm.states.Count > 0) {
+ var prev = vm.states.Last();
+ names = prev.vars.Map(v => v.realName);
+ }
+
+ names = names.Concat(state.Variables).Distinct();
+
+ var curVars = state.Variables.ToDictionary(x => x);
+ foreach (var v in names) {
+ var localName = vm.GetUserVariableName(v);
+ if (localName != null) {
+ var tp = vm.LocalType(v);
+ var val = state.TryGet(v);
+ val = vm.WrapForUse(val, tp);
+ var vn = new VariableNode(this, v, val, tp) { ShortName = localName };
+ vn.updatedHere = vm.states.Count > 0 && curVars.ContainsKey(v);
+ if (curVars.ContainsKey(v))
+ vm.RegisterLocalValue(vn.Name, val);
+ vars.Add(vn);
+ }
+ }
+
+ vm.Flush(vars);
+
+ commons = new List<ElementNode>();
+ commons.AddRange(vm.CommonNodes(this));
+ }
+
+ public override IEnumerable<IDisplayNode> Nodes
+ {
+ get {
+ return vars.Concat(commons);
+ }
+ }
+
+ public override string CapturedStateName
+ {
+ get
+ {
+ return this.capturedStateName;
+ }
+ }
+ }
+
+ class ElementNode : DisplayNode
+ {
+ protected StateNode stateNode;
+ protected Model.Element tp;
+ protected VccModel vm { get { return stateNode.vm; } }
+
+ public ElementNode(StateNode st, EdgeName name, Model.Element elt, Model.Element tp)
+ : base(st.vm, name, elt)
+ {
+ this.stateNode = st;
+ this.tp = tp;
+ }
+
+ protected override void ComputeChildren()
+ {
+ children.AddRange(vm.GetExpansion(stateNode, element, tp));
+ }
+
+ public override string ToolTip
+ {
+ get
+ {
+ var sb = new StringBuilder();
+ if (tp != null)
+ sb.AppendFormat("Type: {0}\n", vm.TypeName(tp));
+ var i = element as Model.Integer;
+ if (i != null) {
+ var n = System.Numerics.BigInteger.Parse(i.Numeral);
+ sb.AppendFormat("Value: {0} (0x{1:x})\n", n, n);
+ } else if (element != null) {
+ sb.AppendFormat("Value: {0}\n", element);
+ }
+ return sb.ToString();
+ }
+ }
+ }
+
+ class SetsNode : ElementNode
+ {
+ List<Model.Element> refs = new List<Model.Element>();
+
+ public SetsNode(StateNode par, Model.Element elt)
+ : base(par, new EdgeName("\\in ..."), null, null)
+ {
+ children = new List<IDisplayNode>();
+ foreach (var app in vm.f_select_bool.AppsWithArg(1, elt)) {
+ children.Add(
+ new MapletNode(par, new EdgeName(vm, VccModel.selfMarker + " \\in %0", app.Args[0]), app.Result, vm.tp_bool) { Category = NodeCategory.MethodologyProperty });
+ refs.Add(app.Args[0]);
+ }
+ Category = NodeCategory.MethodologyProperty;
+ }
+
+ public override IEnumerable<Model.Element> References
+ {
+ get
+ {
+ return refs;
+ }
+ }
+
+ public bool IsEmpty { get { return children.Count == 0; } }
+ }
+
+
+ class FieldNode : ElementNode
+ {
+ public FieldNode(StateNode par, EdgeName realName, Model.Element elt, Model.Element tp)
+ : base(par, realName, elt, tp)
+ {
+ }
+ }
+
+ class MapletNode : ElementNode
+ {
+ public MapletNode(StateNode par, EdgeName realName, Model.Element elt, Model.Element tp)
+ : base(par, realName, elt, tp)
+ {
+ }
+ }
+
+ class VariableNode : ElementNode
+ {
+ public bool updatedHere;
+ public string realName;
+
+ public VariableNode(StateNode par, string realName, Model.Element elt, Model.Element tp)
+ : base(par, new EdgeName(realName), elt, tp)
+ {
+ this.realName = realName;
+ }
+
+ public override string ShortName
+ {
+ set { this.name = new EdgeName(value); }
+ get { return this.name.ToString(); }
+ }
+ }
+}