@@ -409,7 +409,6 @@ scanTypeDeclName tracer mtexprs = do
409
409
-- * A GIVETH can be referred to in other rules up the scope hierarchy
410
410
-- * The head in DECIDE clauses can also be referred to by other rules in scope hierarchy
411
411
-- * WHERE clauses are local to the rule
412
- --
413
412
renameRules :: (Traversable f ) => Tracer Log -> f Rule -> Renamer (f RnRule )
414
413
renameRules tracer rules = do
415
414
rulesWithLocalDefs <-
443
442
defaults <- assertEmptyList rule. defaults
444
443
symtab <- assertEmptyList rule. symtab
445
444
clauses <- traverse (renameHornClause tracer) rule. clauses
446
- name <- renameMultiTerm tracer rule. name
445
+ name <- renameMultiTerm tracer RootExpression rule. name
447
446
pure $
448
447
Hornlike
449
448
RnHornlike
@@ -504,7 +503,7 @@ renameTypeDeclName :: LS.RuleName -> Renamer RnRuleName
504
503
renameTypeDeclName mtexprs = do
505
504
mt <- assertSingletonMultiTerm mtexprs
506
505
rnTyName <- lookupExistingName (NE. singleton mt) RnType
507
- pure [ RnExprName rnTyName]
506
+ pure $ RnExprName rnTyName
508
507
509
508
renameUpons ::
510
509
Maybe LS. ParamText ->
@@ -574,36 +573,69 @@ renameGivenInlineEnumParamText params = do
574
573
rnParams <- traverse renameEach params
575
574
pure $ RnParamText rnParams
576
575
576
+ -- | Track what "Level" an expression has.
577
+ -- This level merely tracks how deep we are in the program AST.
578
+ -- If we are at the top-level, called 'RootExpression', we sometimes have to handle
579
+ -- certain things differently. For example, if we encounter a '[LS.MultiTerm]' such as:
580
+ --
581
+ -- @
582
+ -- [MTT "f", MTT "a", MTT "b"]
583
+ -- @
584
+ --
585
+ -- Is this a function declaration (e.g., the @f a b@ part of a the haskell expression @f a b = a + b@)
586
+ -- or is this a function application, where @f@ is applied to the variables @a@ and @b@?
587
+ -- Without further context, impossible to tell, but we do want to be able to tell these two cases
588
+ -- apart to simplify transpiler backends.
589
+ -- Thus, we track whether we are at the root of the program AST.
590
+ data ExprLevel
591
+ = -- | We are at the root of an expression tree.
592
+ RootExpression
593
+ | -- | We are in some sub-expression of an expression tree.
594
+ SubExpression
595
+ deriving stock (Eq , Show , Ord , Enum , Bounded )
596
+
597
+ -- | Downgrade any 'ExprLevel' to a 'SubExpression'.
598
+ -- Strictly, speaking, this doesn't need a function, but it reduces a few occurrences
599
+ -- of random constants.
600
+ subExpression :: ExprLevel -> ExprLevel
601
+ subExpression _ = SubExpression
602
+
577
603
renameHornClause :: Tracer Log -> LS. HornClause2 -> Renamer RnHornClause
578
604
renameHornClause tracer hc = do
579
- rnHead <- renameRelationalPredicate tracer hc. hHead
605
+ rnHead <- renameRelationalPredicate tracer RootExpression hc. hHead
580
606
rnBody <- traverse (renameBoolStruct tracer) hc. hBody
581
607
pure $
582
608
RnHornClause
583
609
{ rnHcHead = rnHead
584
610
, rnHcBody = rnBody
585
611
}
586
612
587
- renameRelationalPredicate :: Tracer Log -> LS. RelationalPredicate -> Renamer RnRelationalPredicate
588
- renameRelationalPredicate tracer = \ case
613
+ renameRelationalPredicate :: Tracer Log -> ExprLevel -> LS. RelationalPredicate -> Renamer RnRelationalPredicate
614
+ renameRelationalPredicate tracer exprLvl = \ case
589
615
LS. RPParamText pText ->
590
616
throwError $ UnsupportedRPParamText pText
591
- LS. RPMT mt -> RnRelationalTerm <$> renameMultiTerm tracer mt
617
+ LS. RPMT mt -> RnRelationalTerm <$> renameMultiTerm tracer exprLvl mt
592
618
LS. RPConstraint lhs relationalPredicate rhs -> do
593
- rnLhs <- renameMultiTerm tracer lhs
594
- rnRhs <- renameMultiTerm tracer rhs
619
+ rnLhs <- renameMultiTerm tracer exprLvl lhs
620
+ rnRhs <- renameMultiTerm tracer (subExpression exprLvl) rhs
595
621
pure $ RnConstraint rnLhs relationalPredicate rnRhs
596
622
LS. RPBoolStructR lhs relationalPredicate rhs -> do
597
- rnLhs <- renameMultiTerm tracer lhs
623
+ rnLhs <- renameMultiTerm tracer exprLvl lhs
598
624
rnRhs <- renameBoolStruct tracer rhs
599
625
pure $ RnBoolStructR rnLhs relationalPredicate rnRhs
600
- LS. RPnary relationalPredicate rhs -> do
601
- rnRhs <- traverse (renameRelationalPredicate tracer) rhs
602
- pure $ RnNary relationalPredicate rnRhs
626
+ LS. RPnary relationalPredicate [] -> pure $ RnNary relationalPredicate []
627
+ LS. RPnary relationalPredicate (lhs : rhs) -> do
628
+ -- We have to handle the first element explicitly and differently.
629
+ -- See 'scanDecideHeadClause', which explains why.
630
+ rnLhs <- renameRelationalPredicate tracer exprLvl lhs
631
+ rnRhs <- traverse (renameRelationalPredicate tracer $ subExpression exprLvl) rhs
632
+ pure $ RnNary relationalPredicate (rnLhs : rnRhs)
603
633
604
634
renameBoolStruct :: Tracer Log -> LS. BoolStructR -> Renamer RnBoolStructR
605
635
renameBoolStruct tracer = \ case
606
- AA. Leaf p -> AA. Leaf <$> renameRelationalPredicate tracer p
636
+ -- No expression in a 'BoolStructR' can be a 'RootExpression' expression.
637
+ -- Thus, we hardcode 'SubExpression' here.
638
+ AA. Leaf p -> AA. Leaf <$> renameRelationalPredicate tracer SubExpression p
607
639
AA. All lbl cs -> do
608
640
rnBoolStruct <- traverse (renameBoolStruct tracer) cs
609
641
pure $ AA. All lbl rnBoolStruct
@@ -634,8 +666,17 @@ renameBoolStruct tracer = \case
634
666
-- For example, @[MTT "x", MTT "f"]@ will be changed @[MTT "f", MTT "x"]@,
635
667
-- if and only if @"f"@ is a known function variable in scope with associated
636
668
-- arity information.
637
- renameMultiTerm :: Tracer Log -> LS. MultiTerm -> Renamer RnMultiTerm
638
- renameMultiTerm tracer multiTerms = do
669
+ --
670
+ -- At last, we perform an additional translation which turns the list representation
671
+ -- of 'LS.MultiTerm' into a proper AST with dedicated constructors for function
672
+ -- application, record projection and variables.
673
+ -- We use the 'ExprLevel' to resolve an 'LS.MultiTerm' to either a function
674
+ -- declaration or a function application. If the Renamer is currently renaming
675
+ -- a root expression, for example the head of a `DECIDE` clause, then we may be
676
+ -- introducing a function declaration.
677
+ -- Otherwise, we know there can only be function applications.
678
+ renameMultiTerm :: Tracer Log -> ExprLevel -> LS. MultiTerm -> Renamer RnExpr
679
+ renameMultiTerm tracer exprLvl multiTerms = do
639
680
(reversedRnMultiTerms, ctx) <-
640
681
foldM
641
682
( \ (results, state) mt -> do
@@ -646,57 +687,94 @@ renameMultiTerm tracer multiTerms = do
646
687
multiTerms
647
688
let
648
689
rnMultiTerms = reverse reversedRnMultiTerms
649
- fixFixity ctx rnMultiTerms
690
+ multiTermsFixed <- fixFixity ctx rnMultiTerms
691
+
692
+ case multiTermsFixed of
693
+ [expr]
694
+ | Just nameOrLitOrBuiltin <- isNameOrLitOrBuiltin expr -> pure nameOrLitOrBuiltin
695
+ (varName : attrs)
696
+ | Just (name, sels) <- isProjection varName attrs -> pure $ RnProjection name sels
697
+ (varName : args)
698
+ | Just (name, argExprs) <- isFunctionApp varName args
699
+ , mustBeFunctionApplication ->
700
+ pure $ RnFunApp name argExprs
701
+ (varName : args)
702
+ | Just (name, argExprs) <- isFunctionDecl varName args
703
+ , mustBeFunctionDeclaration ->
704
+ pure $ RnFunDecl name argExprs
705
+ exprs -> throwError $ UnknownTermStructure exprs
650
706
where
651
- -- Fixing the arity of a function requires us rewrite infix and postfix
652
- -- notation to a prefix notation.
653
- --
654
- -- To rewrite a function application, we first gather the 'FuncInfo' to
655
- -- find the declared arity of the function. Say the arity of the function @f@ is
656
- -- given by the tuple @(p, q)@ where @p@ is the number of arguments before the
657
- -- function name and @q@ is the number of arguments after the function name.
658
- -- This captures functions applied in prefix, infix and postfix notation.
659
- -- Then, we find the index of the function name as it occurs in the 'LS.MultiTerm'
660
- -- and take @p@ elements from the back of the list of @[LS.MTExpr]@ that occur before
661
- -- the function, which we name @ps@, and take @q@ elements from the list of
662
- -- @[LS.MTExpr]@ that occur after the function name, called @qs@.
663
- --
664
- -- Finally, we replace the function application by @[f] ++ ps ++ qs@.
665
- fixFixity ctx rnMultiTerms = case ctx. multiTermContextFunctionCall of
666
- Nothing -> pure rnMultiTerms
667
- Just fnName -> do
668
- funcInfo <- lookupExistingFunction fnName
669
- let
670
- (preNum, postNum) = funcInfo ^. funcArity
671
- (lhs, fnExpr, rhs) <- findFunctionApplication fnName rnMultiTerms
672
- (leftNonArgs, leftArgs) <- processLhs fnName preNum lhs
673
- (rightNonArgs, rightArgs) <- processRhs fnName postNum rhs
674
- pure $ reverse leftNonArgs <> [fnExpr] <> leftArgs <> rightArgs <> rightNonArgs
707
+ mustBeFunctionApplication = exprLvl == SubExpression
708
+ mustBeFunctionDeclaration = not mustBeFunctionApplication
709
+
710
+ isProjection var sels = do
711
+ varName <- isVariableName var
712
+ selNames <- traverse isSelectorName sels
713
+ Just (varName, selNames)
714
+
715
+ isFunctionApp var args = do
716
+ varName <- isFunctionName var
717
+ Just (varName, args)
675
718
676
- findFunctionApplication fnName rnMultiTerms = do
719
+ isFunctionDecl var args = do
720
+ varName <- isFunctionName var
721
+ argNames <- traverse isVariableName args
722
+ Just (varName, argNames)
723
+
724
+ -- | Fixing the arity of a function requires us rewrite infix and postfix
725
+ -- notation to a prefix notation.
726
+ --
727
+ -- To rewrite a function application, we first gather the 'FuncInfo' to
728
+ -- find the declared arity of the function. Say the arity of the function @f@ is
729
+ -- given by the tuple @(p, q)@ where @p@ is the number of arguments before the
730
+ -- function name and @q@ is the number of arguments after the function name.
731
+ -- This captures functions applied in prefix, infix and postfix notation.
732
+ -- Then, we find the index of the function name as it occurs in the 'LS.MultiTerm'
733
+ -- and take @p@ elements from the back of the list of @[LS.MTExpr]@ that occur before
734
+ -- the function, which we name @ps@, and take @q@ elements from the list of
735
+ -- @[LS.MTExpr]@ that occur after the function name, called @qs@.
736
+ --
737
+ -- Finally, we replace the function application by @[f] ++ ps ++ qs@.
738
+ fixFixity :: MultiTermContext -> [RnExpr ] -> Renamer [RnExpr ]
739
+ fixFixity ctx rnMultiTerms = case ctx. multiTermContextFunctionCall of
740
+ Nothing -> pure rnMultiTerms
741
+ Just fnName -> do
742
+ funcInfo <- lookupExistingFunction fnName
677
743
let
678
- (preArgs, postArgsWithName) = List. break (== (RnExprName fnName)) rnMultiTerms
679
- case postArgsWithName of
680
- [] -> throwError $ FixArityFunctionNotFound fnName rnMultiTerms
681
- (fnExpr : postArgs) -> pure (preArgs, fnExpr, postArgs)
682
-
683
- processLhs name n lhs = do
684
- case safeSplitAt n (reverse lhs) of
685
- Nothing ->
686
- throwError $ ArityErrorLeft n name lhs
687
- Just (args, nonArgs) -> pure (reverse nonArgs, reverse args)
688
-
689
- processRhs name n rhs = do
690
- case safeSplitAt n rhs of
691
- Nothing ->
692
- throwError $ ArityErrorRight n name rhs
693
- Just (nonArgs, args) -> pure (nonArgs, args)
694
-
695
- initialMultiTermContext =
696
- MultiTermContext
697
- { multiTermContextInSelector = False
698
- , multiTermContextFunctionCall = Nothing
699
- }
744
+ (preNum, postNum) = funcInfo ^. funcArity
745
+ (lhs, fnExpr, rhs) <- findFunctionApplication fnName rnMultiTerms
746
+ (leftNonArgs, leftArgs) <- processLhs fnName preNum lhs
747
+ (rightNonArgs, rightArgs) <- processRhs fnName postNum rhs
748
+ pure $ reverse leftNonArgs <> [fnExpr] <> leftArgs <> rightArgs <> rightNonArgs
749
+
750
+ findFunctionApplication :: RnName -> [RnExpr ] -> Renamer ([RnExpr ], RnExpr , [RnExpr ])
751
+ findFunctionApplication fnName rnMultiTerms = do
752
+ let
753
+ (preArgs, postArgsWithName) = List. break (== (RnExprName fnName)) rnMultiTerms
754
+ case postArgsWithName of
755
+ [] -> throwError $ FixArityFunctionNotFound fnName rnMultiTerms
756
+ (fnExpr : postArgs) -> pure (preArgs, fnExpr, postArgs)
757
+
758
+ processLhs :: RnName -> Int -> [RnExpr ] -> Renamer ([RnExpr ], [RnExpr ])
759
+ processLhs name n lhs = do
760
+ case safeSplitAt n (reverse lhs) of
761
+ Nothing ->
762
+ throwError $ ArityErrorLeft n name lhs
763
+ Just (args, nonArgs) -> pure (reverse nonArgs, reverse args)
764
+
765
+ processRhs :: RnName -> Int -> [RnExpr ] -> Renamer ([RnExpr ], [RnExpr ])
766
+ processRhs name n rhs = do
767
+ case safeSplitAt n rhs of
768
+ Nothing ->
769
+ throwError $ ArityErrorRight n name rhs
770
+ Just (nonArgs, args) -> pure (nonArgs, args)
771
+
772
+ initialMultiTermContext :: MultiTermContext
773
+ initialMultiTermContext =
774
+ MultiTermContext
775
+ { multiTermContextInSelector = False
776
+ , multiTermContextFunctionCall = Nothing
777
+ }
700
778
701
779
-- | Rename a single 'LS.MTExpr' to a 'RnExpr'.
702
780
renameMultiTermExpression :: Tracer Log -> MultiTermContext -> LS. MTExpr -> Renamer (RnExpr , MultiTermContext )
@@ -754,6 +832,7 @@ renameMultiTermExpression tracer ctx = \case
754
832
where
755
833
-- There is no doubt this is a text literal, if it is enclosed in quotes.
756
834
-- Strips away the quotes.
835
+ -- TODO: this is lossy, we can never rebuild the exact AST with this.
757
836
isTextLiteral t = do
758
837
(' "' , t') <- uncons t
759
838
(t'', ' "' ) <- unsnoc t'
@@ -775,6 +854,7 @@ data RenamerError
775
854
| UnexpectedRnNameNotFound RnName
776
855
| InsertNameUnexpectedType RnNameType RnNameType
777
856
| LookupOrInsertNameUnexpectedType RnNameType RnNameType
857
+ | UnknownTermStructure [RnExpr ]
778
858
| AssertErr AssertionError
779
859
deriving (Show , Eq , Ord )
780
860
@@ -836,6 +916,8 @@ renderRenamerError = \case
836
916
<> Text. pack (show actual)
837
917
<> " but expected: "
838
918
<> Text. pack (show expected)
919
+ UnknownTermStructure terms ->
920
+ " Renamed the terms " <> Text. pack (show terms) <> " but failed to determine the program structure."
839
921
AssertErr err -> renderAssertionError err
840
922
841
923
renderAssertionError :: AssertionError -> Text. Text
@@ -976,7 +1058,8 @@ recordScopeTable act = do
976
1058
prevUnique <- use scUniqueSupply
977
1059
a <- act
978
1060
scTable <- use scScopeTable
979
- let scTableWithNewNames = filterScopeTable (\ _ name -> name. rnUniqueId >= prevUnique) scTable
1061
+ let
1062
+ scTableWithNewNames = filterScopeTable (\ _ name -> name. rnUniqueId >= prevUnique) scTable
980
1063
pure (a, scTableWithNewNames)
981
1064
982
1065
recordScopeTable_ :: Renamer a -> Renamer ScopeTable
0 commit comments