@@ -863,33 +863,38 @@ module DynamoDBFilterExpr {
863863 (x, MakeAttr (s[pos..pos+x]))
864864 }
865865
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|
869870 {
870- if |input| == 0 then
871+ SequenceIsSafeBecauseItIsInMemory (input);
872+ if |input| as uint64 == pos then
871873 0
872- else if input[0 ]. Value? || input[0 ]. Attr? then
874+ else if input[pos ]. Value? || input[pos ]. Attr? then
873875 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
875877 4
876878 else
877879 0
878880 }
879881
880882 // 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|
884887 {
885- if |input| < 5 then
888+ SequenceIsSafeBecauseItIsInMemory (input);
889+ var input_size : uint64 := |input| as uint64;
890+ if input_size < Add (pos, 5) then
886891 None
887892 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);
893898 if 0 < p3 then
894899 Some ((p1, p2, p3))
895900 else
@@ -901,15 +906,17 @@ module DynamoDBFilterExpr {
901906 }
902907
903908 // 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|
905911 {
906- if |input| < 3 then
912+ SequenceIsSafeBecauseItIsInMemory (input);
913+ if |input| as uint64 < Add (pos, 3) then
907914 false
908- else if ! IsVar (input[0 ]) then
915+ else if ! IsVar (input[pos ]) then
909916 false
910- else if input[1] != In then
917+ else if input[pos + 1] != In then
911918 false
912- else if input[2] != Open then
919+ else if input[pos + 2] != Open then
913920 false
914921 else
915922 true
@@ -919,22 +926,23 @@ module DynamoDBFilterExpr {
919926 // transform A BETWEEN X AND Y to BETWEEN(A, X, Y)
920927 function method ConvertToPrefix (input: seq <Token >) : (res : seq < Token> )
921928 {
922- var between := IsBetween (input);
923929 if |input| < 5 then
924930 input
925- else if IsIN (input) then
931+ else if IsIN (input, 0 ) then
926932 [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..])
931933 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..])
933941 }
934942
935943 lemma TestConvertToPrefix3 (input: seq <Token >)
936944 requires input == [MakeAttr ("A"), In, Open, MakeAttr ("B"), Comma, MakeAttr ("C"), Close]
937- ensures IsIN (input)
945+ ensures IsIN (input, 0 )
938946 ensures ConvertToPrefix (input) == [In, Open, MakeAttr ("A"), Comma, MakeAttr ("B"), Comma, MakeAttr ("C"), Close]
939947 {}
940948
@@ -1084,7 +1092,7 @@ module DynamoDBFilterExpr {
10841092 )
10851093 returns (ret : Result< bool , Error> )
10861094 {
1087- ret := InnerEvalExpr (input, [], item, names, values);
1095+ ret := InnerEvalExpr (input, [], item, names, values, 0 );
10881096 }
10891097
10901098 // count the number of strings
@@ -1224,8 +1232,8 @@ module DynamoDBFilterExpr {
12241232
12251233 // true if target in list
12261234 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
12291237 {
12301238 SequenceIsSafeBecauseItIsInMemory (list);
12311239 if |list| as uint64 == pos then
@@ -1484,43 +1492,47 @@ module DynamoDBFilterExpr {
14841492 stack : seq <StackValue >,
14851493 item : DDB .AttributeMap,
14861494 names : Option <DDB .ExpressionAttributeNameMap>,
1487- values : DDB .ExpressionAttributeValueMap
1495+ values : DDB .ExpressionAttributeValueMap,
1496+ pos : uint64
14881497 )
14891498 returns (ret : Result< bool , Error> )
1499+ requires pos as nat <= |input|
1500+ decreases |input| - pos as nat
14901501 {
1491- if 0 == |input| {
1502+ SequenceIsSafeBecauseItIsInMemory (input);
1503+ if pos == |input| as uint64 {
14921504 if 1 == |stack| && stack[0]. Bool? {
14931505 return Success (stack[0].b);
14941506 } else {
14951507 return Failure (E("ended with bad stack"));
14961508 }
14971509 } else {
1498- var t := input[0 ];
1510+ var t := input[pos ];
14991511 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 );
15011513 } 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 );
15031515 } else if IsUnary (t) {
15041516 if 0 == |stack| {
15051517 ret := Failure (E("Empty stack for unary op"));
15061518 } else {
15071519 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 );
15091521 }
15101522 } else if IsBinary (t) {
15111523 if |stack| < 2 {
15121524 ret := Failure (E("Empty stack for binary op"));
15131525 } else {
15141526 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 );
15161528 }
15171529 } else if IsFunction (t) {
15181530 var num_args := NumArgs (t, stack);
15191531 if |stack| < num_args {
15201532 ret := Failure (E("Empty stack for function call"));
15211533 } else {
15221534 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 );
15241536 }
15251537 } else {
15261538 ret := Success (true);
0 commit comments