private void DirectWrite(IList <Expr> indices, Expr value) { var groupedIndices = GroupIndices(indices); // Build the MapStores bottom up /* Example * var m:[int][int][int]bool; * * Assignment m[1][2][3] := false * has the following form as mapstore/mapselect expressions * m[ 1:= m[1][ 2:= m[1][2][3 := false]]] * * As a tree this looks like. * NOTE: * (mapstore <map to base store on> <index>... <value to store>) * (mapselect <map to read> <index>...) * <index> may repreat several times (this is why groupedIndices was computed) * * mapstore * / | \ * m 1 \ * \ * \ * mapstore * / | \ * / 2 \ * mapselect \ * / | \ * m 1 \ * mapstore * / | \ * mapselect 3 false * / | * mapselect 2 * / | * m 1 */ Expr result = value; for (int groupIndex = groupedIndices.Count - 1; groupIndex >= 0; --groupIndex) { // Build the Mapselects necessary for map variables with nested maps Expr readFromMap = ExpressionRepresentation; for (int mapSelectIndex = 0; mapSelectIndex < groupIndex; ++mapSelectIndex) { readFromMap = Builder.MapSelect(readFromMap, groupedIndices[mapSelectIndex].ToArray()); } result = Builder.MapStore(readFromMap, result, groupedIndices[groupIndex].ToArray()); } ExpressionRepresentation = result; }
public virtual Expr MapStore(Expr map, Expr value, params Expr[] indices) { return(UB.MapStore(map, value, indices)); }
public override Expr VisitNAryExpr(NAryExpr node) { // Need to duplicate arguments first (doing post order traversal) var newArgs = new List <Expr>(); foreach (var oldExpr in node.Args) { var newExpr = (Expr)this.Visit(oldExpr); newArgs.Add(newExpr); } // Now can finally duplicate this node now we've done our children if (node.Fun is FunctionCall) { var FC = (FunctionCall)node.Fun; string bvbuiltin = QKeyValue.FindStringAttribute(FC.Func.Attributes, "bvbuiltin"); if (bvbuiltin != null) { return(HandleBvBuiltIns(FC, bvbuiltin, newArgs)); } else { string builtin = QKeyValue.FindStringAttribute(FC.Func.Attributes, "builtin"); if (builtin != null) { return(HandleBuiltIns(FC, builtin, newArgs)); } } // Not a builtin so treat as uninterpreted function call return(Builder.UFC(FC, newArgs.ToArray())); } else if (node.Fun is UnaryOperator) { var U = (UnaryOperator)node.Fun; Debug.Assert(newArgs.Count == 1); switch (U.Op) { case UnaryOperator.Opcode.Neg: return(Builder.Neg(newArgs[0])); case UnaryOperator.Opcode.Not: return(Builder.Not(newArgs[0])); default: throw new NotImplementedException("Unary operator not supported"); } } else if (node.Fun is BinaryOperator) { var B = (BinaryOperator)node.Fun; Debug.Assert(newArgs.Count == 2); switch (B.Op) { // Integer or Real number operators case BinaryOperator.Opcode.Add: return(Builder.Add(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Sub: return(Builder.Sub(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Mul: return(Builder.Mul(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Div: return(Builder.Div(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Mod: return(Builder.Mod(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.RealDiv: return(Builder.RealDiv(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Pow: return(Builder.Pow(newArgs[0], newArgs[1])); // Comparision operators case BinaryOperator.Opcode.Eq: return(Builder.Eq(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Neq: return(Builder.NotEq(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Gt: return(Builder.Gt(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Ge: return(Builder.Ge(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Lt: return(Builder.Lt(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Le: return(Builder.Le(newArgs[0], newArgs[1])); // Bool operators case BinaryOperator.Opcode.And: return(Builder.And(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Or: return(Builder.Or(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Imp: return(Builder.Imp(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Iff: return(Builder.Iff(newArgs[0], newArgs[1])); case BinaryOperator.Opcode.Subtype: throw new NotImplementedException("SubType binary operator support not implemented"); default: throw new NotSupportedException("Binary operator" + B.Op.ToString() + "not supported!"); } } else if (node.Fun is MapStore) { Debug.Assert(newArgs.Count >= 3); // FIXME: We're probably making too many lists/arrays here var map = newArgs[0]; var value = newArgs[newArgs.Count - 1]; // Last argument is value to store var indices = new List <Expr>(); for (int index = 1; index < newArgs.Count - 1; ++index) { indices.Add(newArgs[index]); } Debug.Assert(indices.Count + 2 == newArgs.Count); return(Builder.MapStore(map, value, indices.ToArray())); } else if (node.Fun is MapSelect) { // FIXME: We're probably making too many lists/arrays here Debug.Assert(newArgs.Count >= 2); var map = newArgs[0]; var indices = new List <Expr>(); for (int index = 1; index < newArgs.Count; ++index) { indices.Add(newArgs[index]); } Debug.Assert(indices.Count + 1 == newArgs.Count); return(Builder.MapSelect(map, indices.ToArray())); } else if (node.Fun is IfThenElse) { Debug.Assert(newArgs.Count == 3); return(Builder.IfThenElse(newArgs[0], newArgs[1], newArgs[2])); } else if (node.Fun is TypeCoercion) { // FIXME: Add support for this in the builder // I don't want to put this into the IExprBuilder until I know // exactly how this operator works and how it should be type checked var immutableTC = new NAryExpr(Token.NoToken, node.Fun, newArgs, /*immutable=*/ true); immutableTC.Type = node.Type; return(immutableTC); } else if (node.Fun is ArithmeticCoercion) { Debug.Assert(newArgs.Count == 1); var ac = node.Fun as ArithmeticCoercion; return(Builder.ArithmeticCoercion(ac.Coercion, newArgs[0])); } throw new NotSupportedException("Unsupported NAryExpr"); }