@@ -19,8 +19,7 @@ import L4.Parser.SrcSpan (SrcRange)
19
19
import L4.Print
20
20
import L4.Syntax
21
21
import qualified L4.TypeCheck as TypeCheck
22
-
23
- import Data.Either
22
+ import L4.EvaluateLazy.ContractFrame
24
23
25
24
newtype Eval a = MkEval (EvalState -> IO (Either EvalException a ))
26
25
deriving (Functor , Applicative , Monad , MonadError EvalException , MonadReader EvalState , MonadIO )
@@ -121,7 +120,7 @@ emptyStack = MkStack 0 []
121
120
data Frame =
122
121
BinOp1 BinOp {- -} (Expr Resolved ) Environment
123
122
| BinOp2 BinOp WHNF {- -}
124
- | App1 {- -} [Expr Resolved ] Environment
123
+ | App1 {- -} [Reference ]
125
124
| IfThenElse1 {- -} (Expr Resolved ) (Expr Resolved ) Environment
126
125
| ConsiderWhen1 Reference {- -} (Expr Resolved ) [Branch Resolved ] Environment
127
126
| PatNil0
@@ -134,6 +133,7 @@ data Frame =
134
133
| EqConstructor2 WHNF {- -} [(Reference , Reference )]
135
134
| EqConstructor3 {- -} [(Reference , Reference )]
136
135
| UpdateThunk Reference
136
+ | ContractFrame ContractFrame
137
137
deriving stock Show
138
138
139
139
step :: Eval Int
@@ -353,7 +353,8 @@ forwardExpr env (Lam _ann givens e) =
353
353
forwardExpr env (App _ann n [] ) =
354
354
expectTerm env n >>= evalRef
355
355
forwardExpr env (App _ann n es@ (_ : _)) = do
356
- pushFrame (App1 es env)
356
+ rs <- traverse (`allocate_` env) es
357
+ pushFrame (App1 rs)
357
358
forwardExpr env (Var emptyAnno n)
358
359
forwardExpr env (AppNamed ann n [] _) =
359
360
forwardExpr env (App ann n [] )
@@ -382,7 +383,12 @@ forwardExpr env (Where _ann e ds) = do
382
383
env' <- evalRecLocalDecls env ds
383
384
let combinedEnv = Map. union env' env
384
385
forwardExpr combinedEnv e
385
- forwardExpr env (Regulative {}) = do undefined -- TODO:
386
+ forwardExpr env (Regulative _ann (MkObligation _ party action due followup)) = do
387
+ partyR <- allocate_ party env
388
+ actionR <- allocate_ action env
389
+ dueR <- traverse (`allocate_` env) due
390
+ followupR <- allocate_ (fromMaybe fulfilExpr followup) env
391
+ backward (ValObligation partyR actionR dueR followupR)
386
392
387
393
backward :: WHNF -> Eval WHNF
388
394
backward val = withPoppedFrame $ \ case
@@ -392,14 +398,20 @@ backward val = withPoppedFrame $ \ case
392
398
forwardExpr env e2
393
399
Just (BinOp2 binOp val1) -> do
394
400
runBinOp binOp val1 val
395
- Just f@ (App1 es env ) -> do
401
+ Just f@ (App1 rs ) -> do
396
402
case val of
397
403
ValClosure givens e env' -> do
398
- env'' <- matchGivens givens f env es
404
+ env'' <- matchGivens givens f rs
399
405
forwardExpr (Map. union env'' env') e
400
406
ValUnappliedConstructor r -> do
401
- refs <- traverse (flip allocate_ env) es
402
- backward (ValConstructor r refs)
407
+ backward (ValConstructor r rs)
408
+ ValObligation party act due followup -> do
409
+ (evs, time) <- case rs of
410
+ [r, t] -> pure (r, t)
411
+ rs' -> internalException $ RuntimeTypeError $ " expected a list of events, but found: " <> foldMap prettyLayout rs'
412
+ pushFrame (ContractFrame (Contract1 (C1Frame (Right party) (Right act) due followup time)))
413
+ evalRef evs
414
+ v@ (ValConstructor r [] ) | r `sameResolved` TypeCheck. fulfilRef -> pure v
403
415
ValAssumed r ->
404
416
stuckOnAssumed r -- TODO: we can do better here
405
417
res -> internalException (RuntimeTypeError $ " expected a function but found: " <> prettyLayout res)
@@ -490,15 +502,97 @@ backward val = withPoppedFrame $ \ case
490
502
Just (UpdateThunk rf) -> do
491
503
updateThunkToWHNF rf val
492
504
backward val
505
+ Just (ContractFrame cFrame) -> backwardConctractFrame val cFrame
493
506
494
- matchGivens :: GivenSig Resolved -> Frame -> Environment -> [Expr Resolved ] -> Eval Environment
495
- matchGivens (MkGivenSig _ann otns) f env es = do
496
- let
497
- (_tyvars, others) = partitionEithers (TypeCheck. isQuantifier <$> otns)
498
- if length others == length es
507
+ backwardConctractFrame :: Value Reference -> ContractFrame -> Eval WHNF
508
+ backwardConctractFrame val = \ case
509
+ Contract1 (C1Frame party act due followup time) -> do
510
+ case val of
511
+ ValCons e es -> do
512
+ pushCFrame (Contract2 (C2Frame party act due followup es time))
513
+ evalRef e
514
+ ValNil -> do
515
+ party' <- evalRef' party
516
+ act' <- evalRef' act
517
+ due' <- traverse evalRef due
518
+ backward (ValBreached (NoProgress party' act' due'))
519
+ _ -> internalException (RuntimeTypeError $ " expected LIST EVENT but found: " <> prettyLayout val <> " when scrutinizing regulative events" )
520
+ Contract2 (C2Frame party act due followup es time) -> do
521
+ (p, a, t) <- case val of
522
+ ValConstructor n [p, a, t] | n `sameResolved` TypeCheck. eventRef -> pure (p, a, t)
523
+ _ -> internalException (RuntimeTypeError $ " expected an EVENT but found: " <> prettyLayout val <> " when scrutinizing a regulative event" )
524
+ pushCFrame (Contract3 (C3Frame act due followup p a t es time))
525
+ evalRef' party
526
+ Contract3 (C3Frame act due followup p a t es time) -> do
527
+ pushCFrame (Contract4 (C4Frame val act due followup a t es time))
528
+ evalRef p
529
+ Contract4 (C4Frame party act due followup a t es time) -> do
530
+ sameParty <- runBinOpEquals party val
531
+ case boolView sameParty of
532
+ Nothing -> internalException (RuntimeTypeError $ " expected BOOLEAN but found: " <> prettyLayout sameParty)
533
+ Just True -> do
534
+ pushCFrame (Contract5 (C5Frame party due followup val a t es time))
535
+ evalRef' act
536
+ Just False -> continueWithNextEvent (Left party) act due followup es time
537
+ Contract5 (C5Frame party due followup p a t es time) -> do
538
+ pushCFrame (Contract6 (C6Frame party val due followup p t es time))
539
+ evalRef a
540
+ Contract6 (C6Frame party act due followup p t es time) -> do
541
+ sameAct <- runBinOpEquals act val
542
+ case boolView sameAct of
543
+ Nothing -> internalException (RuntimeTypeError $ " expected BOOLEAN but found: " <> prettyLayout sameAct)
544
+ Just True -> case due of
545
+ Just due' -> do
546
+ pushCFrame (Contract7 (C7Frame followup p val t es time))
547
+ evalRef due'
548
+ Nothing -> continueWithFollowup followup es time
549
+ Just False -> continueWithNextEvent (Left party) (Left act) due followup es time
550
+ Contract7 (C7Frame followup p a t es time) -> do
551
+ pushCFrame (Contract8 (C8Frame val followup p a es time))
552
+ evalRef t
553
+ Contract8 (C8Frame due followup p a es time) -> do
554
+ pushCFrame (Contract9 (C9Frame due followup p a val es))
555
+ evalRef time
556
+ Contract9 (C9Frame due followup p a t es) -> do
557
+ let assertTime = \ case
558
+ ValNumber i -> pure i
559
+ v -> internalException (RuntimeTypeError $ " expected a NUMBER but got: " <> prettyLayout v)
560
+ stamp <- assertTime t
561
+ due' <- assertTime due
562
+ time <- assertTime val
563
+ -- TODO: this is not too nice, but not wanting this would require to change `App1` to take MaybeEvaluated's
564
+ timeR <- allocateValue val
565
+ let deadline = time + due'
566
+ if stamp > deadline
567
+ then backward (ValBreached (DeadlineMissed p a t deadline))
568
+ else continueWithFollowup followup es timeR
569
+
570
+ where
571
+ continueWithNextEvent :: MaybeEvaluated -> MaybeEvaluated -> Maybe Reference -> Reference -> Reference -> Reference -> Eval WHNF
572
+ continueWithNextEvent party act due followup es time = do
573
+ pushCFrame (Contract1 (C1Frame party act due followup time))
574
+ evalRef es
575
+
576
+ pushCFrame = pushFrame . ContractFrame
577
+
578
+ continueWithFollowup :: Reference -> Reference -> Reference -> Eval WHNF
579
+ continueWithFollowup followup es time = do
580
+ pushFrame (App1 [es, time])
581
+ evalRef followup
582
+
583
+ evalRef' :: MaybeEvaluated -> Eval WHNF
584
+ evalRef' = either pure evalRef
585
+
586
+ matchGivens :: GivenSig Resolved -> Frame -> [Reference ] -> Eval Environment
587
+ matchGivens (MkGivenSig _ann otns) f es = do
588
+ let others = foldMap (either (const [] ) (\ x -> [fst x]) . TypeCheck. isQuantifier) otns
589
+ matchGivens' others f es
590
+
591
+ matchGivens' :: [Resolved ] -> Frame -> [Reference ] -> Eval (Map Unique Reference )
592
+ matchGivens' ns f rs = do
593
+ if length ns == length rs
499
594
then do
500
- refs <- traverse (flip allocate_ env) es
501
- pure $ Map. fromList (zipWith (\ (r, _) v -> (getUnique r, v)) others refs)
595
+ pure $ Map. fromList (zipWith (\ r v -> (getUnique r, v)) ns rs)
502
596
else do
503
597
pushFrame f -- provides better error context
504
598
internalException (RuntimeTypeError " given signatures' values' lengths do not match" )
@@ -697,6 +791,14 @@ evalDirective _env (StrictEval _ann _expr) =
697
791
pure []
698
792
evalDirective _env (Check _ann _expr) =
699
793
pure []
794
+ evalDirective env (Contract ann expr evs) = do
795
+ evalDirective env (LazyEval ann (contractToEvalDirective expr evs))
796
+
797
+ contractToEvalDirective :: Expr Resolved -> [Event Resolved ] -> Expr Resolved
798
+ contractToEvalDirective contract evs = App emptyAnno TypeCheck. evalContractRef [contract, evListExpr]
799
+ where
800
+ evListExpr = List emptyAnno $ map eventExpr evs
801
+ eventExpr (MkEvent ann party act timestamp) = App ann TypeCheck. eventRef [party, act, timestamp]
700
802
701
803
evalLocalDecl :: Environment -> LocalDecl Resolved -> Eval ()
702
804
evalLocalDecl env (LocalDecide _ann decide) =
@@ -778,17 +880,45 @@ trueExpr = App emptyAnno TypeCheck.trueRef []
778
880
trueVal :: WHNF
779
881
trueVal = ValConstructor TypeCheck. trueRef []
780
882
883
+ fulfilExpr :: Expr Resolved
884
+ fulfilExpr = App emptyAnno TypeCheck. fulfilRef []
885
+
886
+ fulfilVal :: Value a
887
+ fulfilVal = ValConstructor TypeCheck. fulfilRef []
888
+
889
+ -- \d e f. d e f
890
+ evalContractVal :: Value a
891
+ evalContractVal = ValClosure
892
+ (MkGivenSig emptyAnno
893
+ [ MkOptionallyTypedName emptyAnno TypeCheck. dDef Nothing
894
+ , MkOptionallyTypedName emptyAnno TypeCheck. eDef Nothing
895
+ , MkOptionallyTypedName emptyAnno TypeCheck. f'Def Nothing
896
+ ]
897
+ )
898
+ (App emptyAnno TypeCheck. dRef [App emptyAnno TypeCheck. eRef [] , App emptyAnno TypeCheck. f'Ref [] ])
899
+ emptyEnvironment
900
+
901
+ -- EVENT :: party -> act -> Number -> EVENT party act
902
+ eventCVal :: Value a
903
+ eventCVal = ValUnappliedConstructor TypeCheck. eventRef
904
+
781
905
-- The initial environment has to be built by pre-allocation.
782
906
initialEnvironment :: Eval Environment
783
907
initialEnvironment = do
784
908
falseRef <- allocateValue falseVal
785
909
trueRef <- allocateValue trueVal
786
910
nilRef <- allocateValue ValNil
911
+ evalContractRef <- allocateValue evalContractVal
912
+ eventCRef <- allocateValue eventCVal
913
+ fulfilRef <- allocateValue fulfilVal
787
914
pure $
788
915
Map. fromList
789
916
[ (TypeCheck. falseUnique, falseRef)
790
917
, (TypeCheck. trueUnique, trueRef)
791
918
, (TypeCheck. emptyUnique, nilRef)
919
+ , (TypeCheck. evalContractUnique, evalContractRef)
920
+ , (TypeCheck. eventCUnique, eventCRef)
921
+ , (TypeCheck. fulfilUnique, fulfilRef)
792
922
]
793
923
794
924
-- TODO: This currently allocates the initial environment once per module.
@@ -827,13 +957,32 @@ nfAux d (ValCons r1 r2) = do
827
957
v2 <- evalRef r2 >>= nfAux (d - 1 )
828
958
pure (MkNF (ValCons v1 v2))
829
959
nfAux _d (ValClosure givens e env) = pure (MkNF (ValClosure givens e env))
960
+ nfAux d (ValObligation party act due followup) = do
961
+ party' <- (nfAux (d - 1 ) <=< evalRef) party
962
+ act' <- (nfAux (d - 1 ) <=< evalRef) act
963
+ due' <- traverse (nfAux (d - 1 ) <=< evalRef) due
964
+ followup' <- (nfAux (d - 1 ) <=< evalRef) followup
965
+ pure (MkNF (ValObligation party' act' due' followup'))
830
966
nfAux _d (ValUnappliedConstructor n) = pure (MkNF (ValUnappliedConstructor n))
831
967
nfAux d (ValConstructor n rs) = do
832
968
vs <- traverse (\ r -> evalRef r >>= nfAux (d - 1 )) rs
833
969
pure (MkNF (ValConstructor n vs))
834
970
nfAux _d (ValAssumed n) = pure (MkNF (ValAssumed n))
835
971
nfAux _d (ValEnvironment env) = pure (MkNF (ValEnvironment env))
836
- nfAux _d (ValRegulative ) = pure (MkNF ValRegulative )
972
+ nfAux d (ValBreached r') = do
973
+ let evalAndNF = traverse $ nfAux (d - 1 ) <=< evalRef
974
+ r <- case r' of
975
+ NoProgress party act timestamp -> do
976
+ party' <- evalAndNF party
977
+ act' <- evalAndNF act
978
+ timestamp' <- traverse evalAndNF timestamp
979
+ pure (NoProgress party' act' timestamp')
980
+ DeadlineMissed party act timestamp deadline -> do
981
+ party' <- evalAndNF party
982
+ act' <- evalAndNF act
983
+ timestamp' <- evalAndNF timestamp
984
+ pure (DeadlineMissed party' act' timestamp' deadline)
985
+ pure (MkNF (ValBreached r))
837
986
838
987
-- | Main entry point.
839
988
--
@@ -847,9 +996,9 @@ execEvalModuleWithEnv :: Environment -> Module Resolved -> IO (Environment, [Eva
847
996
execEvalModuleWithEnv env m@ (MkModule _ moduleUri _) = do
848
997
case evalModuleAndDirectives env m of
849
998
MkEval f -> do
850
- initialStack <- newIORef emptyStack
851
- initialSupply <- newIORef 0
852
- r <- f ( MkEvalState moduleUri initialStack initialSupply)
999
+ stack <- newIORef emptyStack
1000
+ supply <- newIORef 0
1001
+ r <- f MkEvalState { moduleUri, stack, supply}
853
1002
case r of
854
1003
Left _exc -> do
855
1004
-- exceptions at the top-level are unusual; after all, we don't actually
@@ -868,7 +1017,7 @@ data EvalDirective =
868
1017
869
1018
data EvalDirectiveResult =
870
1019
MkEvalDirectiveResult
871
- { range :: ! SrcRange -- ^ of the (L)EVAL directive
1020
+ { range :: ! SrcRange -- ^ of the (L)EVAL / CONTRACT directive
872
1021
, result :: Either EvalException NF
873
1022
}
874
1023
deriving stock (Generic , Show )
0 commit comments