@@ -863,33 +863,38 @@ module DynamoDBFilterExpr {
863
863
(x, MakeAttr (s[pos..pos+x]))
864
864
}
865
865
866
- function method {:opaque} VarOrSize (input: seq <Token >)
867
- : (ret : nat )
868
- ensures ret <= |input|
866
+ function method {:opaque} VarOrSize (input: seq <Token >, pos : uint64 )
867
+ : (ret : uint64)
868
+ requires pos as nat <= |input|
869
+ ensures pos as nat + ret as nat <= |input|
869
870
{
870
- if |input| == 0 then
871
+ SequenceIsSafeBecauseItIsInMemory (input);
872
+ if |input| as uint64 == pos then
871
873
0
872
- else if input[0 ]. Value? || input[0 ]. Attr? then
874
+ else if input[pos ]. Value? || input[pos ]. Attr? then
873
875
1
874
- else if 3 < |input| && input[0 ]. Size? && input[1]. Open? && IsVar (input[2]) && input[3]. Close? then
876
+ else if Add (3, pos) < |input| as uint64 && input[pos ]. Size? && input[pos + 1]. Open? && IsVar (input[pos+ 2]) && input[pos + 3]. Close? then
875
877
4
876
878
else
877
879
0
878
880
}
879
881
880
882
// does it start with "A BETWEEN X AND Y"
881
- function method IsBetween (input: seq <Token >)
882
- : (ret : Option< (int , int , int )> )
883
- ensures ret. Some? ==> (ret. value. 0 + ret. value. 1 + ret. value. 2 + 2) <= |input|
883
+ function method IsBetween (input: seq <Token >, pos : uint64 )
884
+ : (ret : Option< (uint64, uint64, uint64)> )
885
+ ensures HasUint64Size (|input|)
886
+ ensures ret. Some? ==> (pos as nat + ret. value. 0 as nat + ret. value. 1 as nat + ret. value. 2 as nat + 2) <= |input|
884
887
{
885
- if |input| < 5 then
888
+ SequenceIsSafeBecauseItIsInMemory (input);
889
+ var input_size : uint64 := |input| as uint64;
890
+ if input_size < Add (pos, 5) then
886
891
None
887
892
else
888
- var p1 := VarOrSize (input);
889
- if 0 < p1 && (p1 + 1 < |input| ) && input[p1]. Between? then
890
- var p2 := VarOrSize (input[ p1+1..] );
891
- if 0 < p2 && (p1+ p2+ 2 < |input| ) && input[p1+ p2+ 1]. And? then
892
- var p3 := VarOrSize (input[ p1+p2+2..] );
893
+ var p1 := VarOrSize (input, pos );
894
+ if 0 < p1 && (Add (pos+p1, 1) < input_size ) && input[pos + p1]. Between? then
895
+ var p2 := VarOrSize (input, pos+ p1+1);
896
+ if 0 < p2 && (Add (pos+ p1+p2, 2) < input_size ) && input[pos + p1+ p2+ 1]. And? then
897
+ var p3 := VarOrSize (input, pos+ p1+p2+2);
893
898
if 0 < p3 then
894
899
Some ((p1, p2, p3))
895
900
else
@@ -901,15 +906,17 @@ module DynamoDBFilterExpr {
901
906
}
902
907
903
908
// does it start with "A IN ("
904
- predicate method IsIN (input: seq <Token >)
909
+ predicate method IsIN (input: seq <Token >, pos : uint64 )
910
+ requires pos as nat < |input|
905
911
{
906
- if |input| < 3 then
912
+ SequenceIsSafeBecauseItIsInMemory (input);
913
+ if |input| as uint64 < Add (pos, 3) then
907
914
false
908
- else if ! IsVar (input[0 ]) then
915
+ else if ! IsVar (input[pos ]) then
909
916
false
910
- else if input[1] != In then
917
+ else if input[pos + 1] != In then
911
918
false
912
- else if input[2] != Open then
919
+ else if input[pos + 2] != Open then
913
920
false
914
921
else
915
922
true
@@ -919,22 +926,23 @@ module DynamoDBFilterExpr {
919
926
// transform A BETWEEN X AND Y to BETWEEN(A, X, Y)
920
927
function method ConvertToPrefix (input: seq <Token >) : (res : seq < Token> )
921
928
{
922
- var between := IsBetween (input);
923
929
if |input| < 5 then
924
930
input
925
- else if IsIN (input) then
931
+ else if IsIN (input, 0 ) then
926
932
[input[1], input[2], input[0], Comma] + ConvertToPrefix (input[3..])
927
- else if between. Some? then
928
- var b := between. value;
929
- [Between, Open] + input[0.. b. 0] + [Comma] + input[b. 0+ 1.. b. 0+ b. 1+ 1] + [Comma]
930
- + input[b. 0+ b. 1+ 2.. b. 0+ b. 1+ b. 2+ 2] + [Close] + ConvertToPrefix (input[b.0+b.1+b.2+2..])
931
933
else
932
- [input[0]] + ConvertToPrefix (input[1..])
934
+ var between := IsBetween (input, 0);
935
+ if between. Some? then
936
+ var b := between. value;
937
+ [Between, Open] + input[0.. b. 0] + [Comma] + input[b. 0+ 1.. b. 0+ b. 1+ 1] + [Comma]
938
+ + input[b. 0+ b. 1+ 2.. b. 0+ b. 1+ b. 2+ 2] + [Close] + ConvertToPrefix (input[b.0+b.1+b.2+2..])
939
+ else
940
+ [input[0]] + ConvertToPrefix (input[1..])
933
941
}
934
942
935
943
lemma TestConvertToPrefix3 (input: seq <Token >)
936
944
requires input == [MakeAttr ("A"), In, Open, MakeAttr ("B"), Comma, MakeAttr ("C"), Close]
937
- ensures IsIN (input)
945
+ ensures IsIN (input, 0 )
938
946
ensures ConvertToPrefix (input) == [In, Open, MakeAttr ("A"), Comma, MakeAttr ("B"), Comma, MakeAttr ("C"), Close]
939
947
{}
940
948
@@ -1084,7 +1092,7 @@ module DynamoDBFilterExpr {
1084
1092
)
1085
1093
returns (ret : Result< bool , Error> )
1086
1094
{
1087
- ret := InnerEvalExpr (input, [], item, names, values);
1095
+ ret := InnerEvalExpr (input, [], item, names, values, 0 );
1088
1096
}
1089
1097
1090
1098
// count the number of strings
@@ -1224,8 +1232,8 @@ module DynamoDBFilterExpr {
1224
1232
1225
1233
// true if target in list
1226
1234
predicate method is_in (target : DDB .AttributeValue, list : seq <StackValue >, pos : uint64 := 0)
1227
- requires pos as nat <= |list|
1228
- decreases |list| - pos as nat
1235
+ requires pos as nat <= |list|
1236
+ decreases |list| - pos as nat
1229
1237
{
1230
1238
SequenceIsSafeBecauseItIsInMemory (list);
1231
1239
if |list| as uint64 == pos then
@@ -1484,43 +1492,47 @@ module DynamoDBFilterExpr {
1484
1492
stack : seq <StackValue >,
1485
1493
item : DDB .AttributeMap,
1486
1494
names : Option <DDB .ExpressionAttributeNameMap>,
1487
- values : DDB .ExpressionAttributeValueMap
1495
+ values : DDB .ExpressionAttributeValueMap,
1496
+ pos : uint64
1488
1497
)
1489
1498
returns (ret : Result< bool , Error> )
1499
+ requires pos as nat <= |input|
1500
+ decreases |input| - pos as nat
1490
1501
{
1491
- if 0 == |input| {
1502
+ SequenceIsSafeBecauseItIsInMemory (input);
1503
+ if pos == |input| as uint64 {
1492
1504
if 1 == |stack| && stack[0]. Bool? {
1493
1505
return Success (stack[0].b);
1494
1506
} else {
1495
1507
return Failure (E("ended with bad stack"));
1496
1508
}
1497
1509
} else {
1498
- var t := input[0 ];
1510
+ var t := input[pos ];
1499
1511
if t. Value? {
1500
- ret := InnerEvalExpr (input[1..] , stack + [StackValueFromValue(t.s, values)], item, names, values);
1512
+ ret := InnerEvalExpr (input, stack + [StackValueFromValue(t.s, values)], item, names, values, pos + 1 );
1501
1513
} else if t. Attr? {
1502
- ret := InnerEvalExpr (input[1..] , stack + [StackValueFromAttr(t, item, names)], item, names, values);
1514
+ ret := InnerEvalExpr (input, stack + [StackValueFromAttr(t, item, names)], item, names, values, pos + 1 );
1503
1515
} else if IsUnary (t) {
1504
1516
if 0 == |stack| {
1505
1517
ret := Failure (E("Empty stack for unary op"));
1506
1518
} else {
1507
1519
var val :- apply_unary (t, stack[|stack|-1]);
1508
- ret := InnerEvalExpr (input[1..] , stack[..|stack|-1] + [val], item, names, values);
1520
+ ret := InnerEvalExpr (input, stack[..|stack|-1] + [val], item, names, values, pos+1 );
1509
1521
}
1510
1522
} else if IsBinary (t) {
1511
1523
if |stack| < 2 {
1512
1524
ret := Failure (E("Empty stack for binary op"));
1513
1525
} else {
1514
1526
var val :- apply_binary (t, stack[|stack|-2], stack[|stack|-1]);
1515
- ret := InnerEvalExpr (input[1..] , stack[..|stack|-2] + [val], item, names, values);
1527
+ ret := InnerEvalExpr (input, stack[..|stack|-2] + [val], item, names, values, pos+1 );
1516
1528
}
1517
1529
} else if IsFunction (t) {
1518
1530
var num_args := NumArgs (t, stack);
1519
1531
if |stack| < num_args {
1520
1532
ret := Failure (E("Empty stack for function call"));
1521
1533
} else {
1522
1534
var val :- apply_function (t, stack, num_args);
1523
- ret := InnerEvalExpr (input[1..] , stack[..|stack|-num_args] + [val], item, names, values);
1535
+ ret := InnerEvalExpr (input, stack[..|stack|-num_args] + [val], item, names, values, pos+1 );
1524
1536
}
1525
1537
} else {
1526
1538
ret := Success (true);
0 commit comments