Skip to content
This repository was archived by the owner on Jan 9, 2026. It is now read-only.

Commit b8636a6

Browse files
authored
FV remove enumerate shim (#1155)
1 parent a7ef270 commit b8636a6

File tree

7 files changed

+143
-2
lines changed

7 files changed

+143
-2
lines changed

src-tool/Pact/Analyze/Eval/Core.hs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,27 @@ evalCore (Compose tya tyb _ a (Open vida _nma tmb) (Open vidb _nmb tmc)) = do
163163
b' <- withVar vida (mkAVal a') $ withSing tyb $ eval tmb
164164
withVar vidb (mkAVal b') $ eval tmc
165165
evalCore (StrConcat p1 p2) = (.++) <$> eval p1 <*> eval p2
166+
167+
evalCore (Enumerate from to step) = do
168+
S _ from' <- eval from
169+
S _ to' <- eval to
170+
S _ step' <- eval step
171+
let
172+
go :: (forall v. OrdSymbolic v => v -> v -> SBV Bool) -> SBV Integer -> SBV Integer -> SBV Integer -> SBV [Integer]
173+
go cmp b e s = ite (b `cmp` e) (b SBVL..: go cmp (b + s) e s) SBVL.nil
174+
175+
let algPos = ite (from' .== to') (SBVL.singleton from')
176+
(ite (step' .== 0) (SBVL.singleton from' )
177+
(ite (from' + step' .> to') (SBVL.singleton from') (go (.<=) from' to' step')))
178+
179+
algNeg = ite (step' .== 0) (SBVL.singleton from' )
180+
(ite (from' + step' .< to') (SBVL.singleton from') (go (.>=) from' to' step'))
181+
182+
183+
markFailure $ (from' .< to' .&& step' .< 0) .|| (from' .> to' .&& step' .> 0)
184+
185+
pure $ sansProv (ite (from' .<= to') algPos algNeg)
186+
166187
evalCore (StrLength p)
167188
= over s2Sbv SBVS.length . coerceS @Str @String <$> eval p
168189
evalCore (StrToInt s) = evalStrToInt s

src-tool/Pact/Analyze/Feature.hs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ data Feature
110110
| FListProjection
111111
| FListLength
112112
| FContains
113+
| FEnumerate
113114
| FReverse
114115
| FSort
115116
| FListDrop
@@ -952,6 +953,22 @@ doc FContains = Doc
952953
]
953954
(TyCon bool)
954955
]
956+
doc FEnumerate = Doc
957+
"enumerate"
958+
CList
959+
InvAndProp
960+
"Returns a sequence of numbers as a list"
961+
[ Usage
962+
"(drop n xs)"
963+
Map.empty
964+
$ Fun
965+
Nothing
966+
[ ("from", TyCon int)
967+
, ("to" , TyCon int)
968+
, ("step", TyCon int)
969+
]
970+
(TyList' (TyCon int))
971+
]
955972

956973
doc FReverse = Doc
957974
"reverse"
@@ -1736,6 +1753,7 @@ PAT(SOrQ, FOrQ)
17361753
PAT(SObjectProjection, FObjectProjection)
17371754
PAT(SListLength, FListLength)
17381755
PAT(SContains, FContains)
1756+
PAT(SEnumerate, FEnumerate)
17391757
PAT(SReverse, FReverse)
17401758
PAT(SSort, FSort)
17411759
PAT(SListDrop, FListDrop)

src-tool/Pact/Analyze/Parse/Prop.hs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,18 @@ inferPreProp preProp = case preProp of
393393
-- applications:
394394
--
395395
-- Function types are inferred; arguments are checked.
396+
397+
PreApp s args
398+
| s == SEnumerate -> do
399+
args' <- for args $ \arg -> inferPreProp arg >>= \case
400+
Some SInteger i -> pure i
401+
_otherwise -> throwErrorIn preProp "expected integer arguments"
402+
403+
case args' of
404+
[from, to] -> pure $ Some (SList SInteger) $ CoreProp $ Enumerate from to (Lit' 1)
405+
[from, to, step] -> pure $ Some (SList SInteger) $ CoreProp $ Enumerate from to step
406+
_otherwise -> throwErrorIn preProp "expected 2 or 3 integer arguments"
407+
396408
PreApp s [arg] | s == SStringLength -> do
397409
arg' <- inferPreProp arg
398410
case arg' of

src-tool/Pact/Analyze/PrenexNormalize.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ singFloat ty p = case p of
126126
CoreProp <$> (ListEqNeq ty' op <$> singFloat (SList ty') a <*> singFloat (SList ty') b)
127127
CoreProp (StrContains needle haystack) -> CoreProp <$>
128128
(StrContains <$> float needle <*> float haystack)
129+
CoreProp (Enumerate from to step) -> CoreProp <$>
130+
(Enumerate <$> float from <*> float to <*> float step)
129131
CoreProp (ListContains ty' needle haystack) ->
130132
CoreProp <$> (ListContains ty' <$> singFloat ty' needle <*> singFloat (SList ty') haystack)
131133

src-tool/Pact/Analyze/Translate.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1714,8 +1714,14 @@ translateNode astNode = withAstContext astNode $ case astNode of
17141714
Some ty@(SList elemTy) l -> pure $ Some ty $ CoreTerm $ ListDistinct elemTy l
17151715
_ -> unexpectedNode astNode
17161716

1717-
AST_NFun node fn@"enumerate" args ->
1718-
shimNative' node fn args "[0]" (Some (SList SInteger) (Lit' [0]))
1717+
AST_NFun _node _fn@"enumerate" args -> do
1718+
args' <- for args $ \arg -> translateNode arg >>= \case
1719+
Some SInteger i' -> pure i'
1720+
_otherwise -> unexpectedNode astNode
1721+
case args' of
1722+
[from, to'] -> pure $ Some (SList SInteger) $ CoreTerm $ Enumerate from to' (Lit' 1)
1723+
[from, to', step] -> pure $ Some (SList SInteger) $ CoreTerm $ Enumerate from to' step
1724+
_otherwise -> unexpectedNode astNode
17191725

17201726
AST_NFun node fn@"format" [a, b] -> translateNode a >>= \a' -> case a' of
17211727
-- uncaught case is dynamic list, sub format string

src-tool/Pact/Analyze/Types/Languages.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ data Core (t :: Ty -> K.Type) (a :: Ty) where
206206
StrToIntBase :: t 'TyInteger -> t 'TyStr -> Core t 'TyInteger
207207
StrContains :: t 'TyStr -> t 'TyStr -> Core t 'TyBool
208208

209+
Enumerate :: t 'TyInteger -> t 'TyInteger -> t 'TyInteger -> Core t ('TyList 'TyInteger)
210+
209211
-- numeric ops
210212
Numerical :: Numerical t a -> Core t a
211213

@@ -721,6 +723,7 @@ showsPrecCore ty p core = showParen (p > 10) $ case core of
721723
StrToInt a -> showString "StrToInt " . showsTm 11 a
722724
StrToIntBase a b -> showString "StrToIntBase " . showsTm 11 a . showChar ' ' . showsTm 11 b
723725
StrContains a b -> showString "StrContains " . showsTm 11 a . showChar ' ' . showsTm 11 b
726+
Enumerate a b c -> showString "Enumerate " . showsTm 11 a . showChar ' ' . showsTm 11 b . showChar ' ' . showsTm 11 c
724727
Numerical a -> showString "Numerical " . showsNumerical ty 11 a
725728
IntAddTime a b -> showString "IntAddTime " . showsTm 11 a . showChar ' ' . showsTm 11 b
726729
DecAddTime a b -> showString "DecAddTime " . showsTm 11 a . showChar ' ' . showsTm 11 b
@@ -964,6 +967,7 @@ prettyCore ty = \case
964967
StrToIntBase b s -> parensSep [pretty SStringToInteger, prettyTm b, prettyTm s]
965968
StrContains needle haystack
966969
-> parensSep [pretty SContains, prettyTm needle, prettyTm haystack]
970+
Enumerate x y z -> parensSep [pretty SEnumerate, prettyTm x, prettyTm y, prettyTm z]
967971
Numerical tm -> prettyNumerical ty tm
968972
IntAddTime x y -> parensSep [pretty STemporalAddition, prettyTm x, prettyTm y]
969973
DecAddTime x y -> parensSep [pretty STemporalAddition, prettyTm x, prettyTm y]
@@ -1830,6 +1834,8 @@ propToInvariant (CoreProp core) = CoreInvariant <$> case core of
18301834
StrToIntBase <$> f tm1 <*> f tm2
18311835
StrContains tm1 tm2 ->
18321836
StrContains <$> f tm1 <*> f tm2
1837+
Enumerate tm1 tm2 tm3 ->
1838+
Enumerate <$> f tm1 <*> f tm2 <*> f tm3
18331839
Numerical num ->
18341840
Numerical <$> numF num
18351841
IntAddTime tm1 tm2 ->

tests/AnalyzeSpec.hs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3672,6 +3672,82 @@ spec = describe "analyze" $ do
36723672
-- we expect this to give an error
36733673
expectVerified code
36743674

3675+
describe "enumeration positive" $ do
3676+
let code model =
3677+
[text|
3678+
(defun test:[integer] ()
3679+
@model $model
3680+
(enumerate 0 10 1))
3681+
|]
3682+
expectVerified $ code "[(property (= result (enumerate 0 10)))]"
3683+
expectVerified $ code "[(property (= result (enumerate 0 10 1)))]"
3684+
3685+
describe "enumeration positive (FROM = TO)" $ do
3686+
let code model =
3687+
[text|
3688+
(defun test:[integer] ()
3689+
@model $model
3690+
(enumerate 10 10))
3691+
|]
3692+
expectVerified $ code "[(property (= result [10]))]"
3693+
3694+
describe "enumeration positive (INC = 0)" $ do
3695+
let code model =
3696+
[text|
3697+
(defun test:[integer] ()
3698+
@model $model
3699+
(enumerate 10 10 0))
3700+
|]
3701+
expectVerified $ code "[(property (= result [10]))]"
3702+
3703+
describe "enumeration positive (FROM + INC > TO)" $ do
3704+
let code model =
3705+
[text|
3706+
(defun test:[integer] ()
3707+
@model $model
3708+
(enumerate 10 15 10))
3709+
|]
3710+
expectVerified $ code "[(property (= result [10]))]"
3711+
3712+
3713+
describe "enumeration negative" $ do
3714+
let code model =
3715+
[text|
3716+
(defun test:[integer] ()
3717+
@model $model
3718+
(enumerate 10 1 -1))
3719+
|]
3720+
expectVerified $ code "[(property (= result (enumerate 10 1 -1)))]"
3721+
expectVerified $ code "[(property (= result [10 9 8 7 6 5 4 3 2 1]))]"
3722+
3723+
describe "enumeration negative should fail" $ do
3724+
let code =
3725+
[text|
3726+
(defun test:[integer] ()
3727+
@model [(property (= result (enumerate 10 1 1))]
3728+
(enumerate 10 1 1))
3729+
|]
3730+
expectFalsified code
3731+
describe "enumeration positive should fail" $ do
3732+
let code =
3733+
[text|
3734+
(defun test:[integer] ()
3735+
@model [(property (= result (enumerate 1 10 -1))]
3736+
(enumerate 1 10 -1))
3737+
|]
3738+
expectFalsified code
3739+
3740+
describe "enumeration positiv with step" $ do
3741+
let code model =
3742+
[text|
3743+
(defun test:[integer] ()
3744+
@model $model
3745+
(enumerate 0 10 2))
3746+
|]
3747+
expectVerified $ code "[(property (= result [0 2 4 6 8 10]))]"
3748+
expectFalsified $ code "[(property (= result []))]"
3749+
3750+
36753751
describe "string drop" $ do
36763752
let code1 model = [text|
36773753
(defun test:string ()

0 commit comments

Comments
 (0)