@@ -82,6 +82,14 @@ public final class CelZ3TypeSystem {
8282 private static final String IS_BYTES = "isBytes" ;
8383 private static final String GET_BYTES = "getBytes" ;
8484
85+ private static final String CONS_TIMESTAMP = "Timestamp" ;
86+ private static final String IS_TIMESTAMP = "isTimestamp" ;
87+ private static final String GET_TIMESTAMP = "getTimestamp" ;
88+
89+ private static final String CONS_DURATION = "Duration" ;
90+ private static final String IS_DURATION = "isDuration" ;
91+ private static final String GET_DURATION = "getDuration" ;
92+
8593 private static final String CONS_ERROR = "CelError" ;
8694 private static final String IS_ERROR = "isError" ;
8795
@@ -170,6 +178,8 @@ public int hashCode() {
170178 private final Constructor doubleCons ;
171179 private final Constructor stringCons ;
172180 private final Constructor bytesCons ;
181+ private final Constructor timestampCons ;
182+ private final Constructor durationCons ;
173183 private final Constructor errorCons ;
174184 private final Constructor unknownCons ;
175185 private final Constructor nullCons ;
@@ -233,30 +243,38 @@ public Sort listRefSort() {
233243 return listRefSort ;
234244 }
235245
236- Constructor boolCons () {
246+ public Constructor boolCons () {
237247 return boolCons ;
238248 }
239249
240- Constructor intCons () {
250+ public Constructor intCons () {
241251 return intCons ;
242252 }
243253
244- Constructor uintCons () {
254+ public Constructor uintCons () {
245255 return uintCons ;
246256 }
247257
248- Constructor doubleCons () {
258+ public Constructor doubleCons () {
249259 return doubleCons ;
250260 }
251261
252- Constructor stringCons () {
262+ public Constructor stringCons () {
253263 return stringCons ;
254264 }
255265
256- Constructor bytesCons () {
266+ public Constructor bytesCons () {
257267 return bytesCons ;
258268 }
259269
270+ public Constructor timestampCons () {
271+ return timestampCons ;
272+ }
273+
274+ public Constructor durationCons () {
275+ return durationCons ;
276+ }
277+
260278 Constructor optionalCons () {
261279 return optionalCons ;
262280 }
@@ -296,6 +314,16 @@ public Expr<?> wrapBytes(Expr<?> expr) {
296314 return ctx .mkApp (bytesCons .ConstructorDecl (), expr );
297315 }
298316
317+ /** Wraps a Z3 integer expression into a timestamp CelValue. */
318+ public Expr <?> wrapTimestamp (IntExpr expr ) {
319+ return ctx .mkApp (timestampCons .ConstructorDecl (), expr );
320+ }
321+
322+ /** Wraps a Z3 integer expression into a duration CelValue. */
323+ public Expr <?> wrapDuration (IntExpr expr ) {
324+ return ctx .mkApp (durationCons .ConstructorDecl (), expr );
325+ }
326+
299327 /** Creates a CelValue containing an integer. */
300328 public Expr <?> mkInt (long val ) {
301329 return ctx .mkApp (intCons .ConstructorDecl (), ctx .mkInt (val ));
@@ -326,8 +354,8 @@ public BoolExpr isDouble(Expr<?> val) {
326354 }
327355
328356 /** Extracts the double reference from a double CelValue. */
329- public Expr <?> getDouble (Expr <?> val ) {
330- return ctx .mkApp (doubleCons .getAccessorDecls ()[0 ], val );
357+ public FPExpr getDouble (Expr <?> val ) {
358+ return ( FPExpr ) ctx .mkApp (doubleCons .getAccessorDecls ()[0 ], val );
331359 }
332360
333361 /**
@@ -372,7 +400,8 @@ public BoolExpr getStructuralEquality(Expr<?> arg0, Expr<?> arg1) {
372400 // Doubles must be compared using native floating-point equality to follow IEEE-754.
373401 // Z3's structural mkEq evaluates NaN == NaN as true and 0.0 == -0.0 as false.
374402 BoolExpr isDoubleEq = ctx .mkAnd (isDouble (arg0 ), isDouble (arg1 ));
375- BoolExpr doubleEq = ctx .mkFPEq ((FPExpr ) getDouble (arg0 ), (FPExpr ) getDouble (arg1 ));
403+ BoolExpr doubleEq = ctx .mkFPEq (getDouble (arg0 ), getDouble (arg1 ));
404+
376405
377406 // For primitives, generic equality matches the direct Z3 datatype wrapper.
378407 BoolExpr genericEq = ctx .mkEq (arg0 , arg1 );
@@ -409,10 +438,14 @@ public Expr<?> mkNull() {
409438 return ctx .mkConst (nullCons .ConstructorDecl ());
410439 }
411440
412- Constructor errorCons () {
441+ public Constructor errorCons () {
413442 return errorCons ;
414443 }
415444
445+ public Constructor nullCons () {
446+ return nullCons ;
447+ }
448+
416449 /** Creates a CelValue representing an unknown value. */
417450 public Expr <?> mkUnknown () {
418451 return mkUnknown (ctx .mkConst (GENERIC_UNKNOWN_ID , unknownIdSort ));
@@ -498,7 +531,7 @@ public Expr<?> withRuntimeError(
498531 return ctx .mkITE (condition , mkError (), result );
499532 }
500533
501- Constructor unknownCons () {
534+ public Constructor unknownCons () {
502535 return unknownCons ;
503536 }
504537
@@ -582,6 +615,26 @@ public IntExpr getUint(Expr<?> val) {
582615 return (IntExpr ) ctx .mkApp (uintCons .getAccessorDecls ()[0 ], val );
583616 }
584617
618+ /** Checks if the given CelValue is a timestamp. */
619+ public BoolExpr isTimestamp (Expr <?> val ) {
620+ return (BoolExpr ) ctx .mkApp (timestampCons .getTesterDecl (), val );
621+ }
622+
623+ /** Extracts the integer expression from a timestamp CelValue. */
624+ public IntExpr getTimestamp (Expr <?> val ) {
625+ return (IntExpr ) ctx .mkApp (timestampCons .getAccessorDecls ()[0 ], val );
626+ }
627+
628+ /** Checks if the given CelValue is a duration. */
629+ public BoolExpr isDuration (Expr <?> val ) {
630+ return (BoolExpr ) ctx .mkApp (durationCons .getTesterDecl (), val );
631+ }
632+
633+ /** Extracts the integer expression from a duration CelValue. */
634+ public IntExpr getDuration (Expr <?> val ) {
635+ return (IntExpr ) ctx .mkApp (durationCons .getAccessorDecls ()[0 ], val );
636+ }
637+
585638 /** Checks if the given CelValue is a string. */
586639 public BoolExpr isString (Expr <?> val ) {
587640 return (BoolExpr ) ctx .mkApp (stringCons .getTesterDecl (), val );
@@ -719,6 +772,19 @@ public BoolExpr checkIntOverflow(ArithExpr result) {
719772 return ctx .mkOr (ctx .mkGt (result , ctx .mkInt (MAX_INT64 )), ctx .mkLt (result , ctx .mkInt (MIN_INT64 )));
720773 }
721774
775+ /** Checks if the given arithmetic expression overflows CEL Timestamp bounds. */
776+ public BoolExpr checkTimestampOverflow (ArithExpr result ) {
777+ return ctx .mkOr (
778+ ctx .mkGt (result , ctx .mkInt (253402300799L )), // 9999-12-31T23:59:59Z
779+ ctx .mkLt (result , ctx .mkInt (-62135596800L ))); // 0001-01-01T00:00:00Z
780+ }
781+
782+ /** Checks if the given arithmetic expression overflows CEL Duration bounds. */
783+ public BoolExpr checkDurationOverflow (ArithExpr result ) {
784+ return ctx .mkOr (
785+ ctx .mkGt (result , ctx .mkInt (315576000000L )), ctx .mkLt (result , ctx .mkInt (-315576000000L )));
786+ }
787+
722788 /** Checks if the given arithmetic expression overflows a 64-bit unsigned integer. */
723789 public BoolExpr checkUintOverflow (ArithExpr result ) {
724790 return ctx .mkOr (ctx .mkGt (result , ctx .mkInt (MAX_UINT64 )), ctx .mkLt (result , ctx .mkInt (0 )));
@@ -890,6 +956,20 @@ public static BoolExpr mkNotFlattened(Context ctx, BoolExpr arg) {
890956 this .bytesCons =
891957 ctx .mkConstructor (
892958 CONS_BYTES , IS_BYTES , new String [] {GET_BYTES }, new Sort [] {ctx .getStringSort ()}, null );
959+ this .timestampCons =
960+ ctx .mkConstructor (
961+ CONS_TIMESTAMP ,
962+ IS_TIMESTAMP ,
963+ new String [] {GET_TIMESTAMP },
964+ new Sort [] {ctx .getIntSort ()},
965+ null );
966+ this .durationCons =
967+ ctx .mkConstructor (
968+ CONS_DURATION ,
969+ IS_DURATION ,
970+ new String [] {GET_DURATION },
971+ new Sort [] {ctx .getIntSort ()},
972+ null );
893973 this .errorCons = ctx .mkConstructor (CONS_ERROR , IS_ERROR , null , null , null );
894974
895975 this .unknownIdSort = ctx .mkUninterpretedSort ("UnknownId" );
@@ -936,6 +1016,8 @@ public static BoolExpr mkNotFlattened(Context ctx, BoolExpr arg) {
9361016 this .doubleCons ,
9371017 this .stringCons ,
9381018 this .bytesCons ,
1019+ this .timestampCons ,
1020+ this .durationCons ,
9391021 this .errorCons ,
9401022 this .unknownCons ,
9411023 this .optionalCons ,
0 commit comments