Skip to content

Commit

Permalink
crude support for custom infix operators
Browse files Browse the repository at this point in the history
  • Loading branch information
flupe committed Mar 9, 2023
1 parent ce1a669 commit 13efde6
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 2 deletions.
31 changes: 29 additions & 2 deletions src/Agda2Hs/Compile/Function.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import qualified Language.Haskell.Exts.Build as Hs
import Agda.Compiler.Backend
import Agda.Compiler.Common

import Agda.Syntax.Common ( NamedArg, namedArg )
import Agda.Syntax.Common
import Agda.Syntax.Internal
import Agda.Syntax.Literal
import Agda.Syntax.Scope.Base ( BindingSource(LambdaBound) )
Expand All @@ -29,6 +29,7 @@ import Agda.TypeChecking.Sort ( ifIsSort )
import Agda.Utils.Functor ( (<&>) )
import Agda.Utils.Impossible ( __IMPOSSIBLE__ )
import Agda.Utils.Pretty ( prettyShow )
import Agda.Utils.Lens ((^.))
import Agda.Utils.List ( snoc )
import Agda.Utils.Monad

Expand Down Expand Up @@ -89,7 +90,33 @@ negSucIntPat _ _ _ = __IMPOSSIBLE__
-- The bool argument says whether we also want the type signature or just the body
compileFun, compileFun' :: Bool -> Definition -> C [Hs.Decl ()]
-- initialize locals when first stepping into a function
compileFun withSig def@Defn{..} = withFunctionLocals defName $ compileFun' withSig def
compileFun withSig def@Defn{..} = setCurrentRangeQ defName $ do
-- check if the function is an operator with custom fixity,
-- then compile the function
maybePrependFixity $ withFunctionLocals defName $ compileFun' withSig def
where
Function{..} = theDef
m = qnameModule defName
n = qnameName defName
f@(Fixity _ lvl assoc) = n ^. lensFixity
x = hsName $ prettyShow n

checkFixityLevel :: FixityLevel -> C (Maybe Int)
checkFixityLevel Unrelated = pure Nothing
checkFixityLevel (Related lvl) =
if lvl /= fromInteger (round lvl) || lvl < 0
then genericDocError =<< text "Invalid fixity" <+> pretty lvl
<+> text "for operator" <+> prettyTCM defName
else pure (Just (round lvl))

maybePrependFixity comp | f /= noFixity = do
hsLvl <- checkFixityLevel lvl
let hsAssoc = case assoc of
NonAssoc -> Hs.AssocNone ()
LeftAssoc -> Hs.AssocLeft ()
RightAssoc -> Hs.AssocRight ()
(Hs.InfixDecl () hsAssoc hsLvl [Hs.VarOp () x]:) <$> comp
maybePrependFixity comp = comp
-- inherit existing (instantiated) locals
compileFun' withSig def@(Defn {..}) = do
reportSDoc "agda2hs.compile" 6 $ text "compiling function: " <+> prettyTCM defName
Expand Down
9 changes: 9 additions & 0 deletions test/Fail/Fixities.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module Fail.Fixities where

open import Haskell.Prelude

infixl 8.5 _<+>_
_<+>_ : Int Int Int
x <+> y = x

{-# COMPILE AGDA2HS _<+>_ #-}
12 changes: 12 additions & 0 deletions test/Fixities.agda
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ mixedAssoc m f = f =<< (((f =<< m) >>= f) >>= f)
{-# COMPILE AGDA2HS rightAssoc #-}
{-# COMPILE AGDA2HS nonAssoc #-}
{-# COMPILE AGDA2HS mixedAssoc #-}

infixl 7 _<+>_
_<+>_ : Int Int Int
x <+> y = x + y

{-# COMPILE AGDA2HS _<+>_ #-}

infixr 8 _<->_
_<->_ : Int Int Int
x <-> y = x - y

{-# COMPILE AGDA2HS _<->_ #-}
2 changes: 2 additions & 0 deletions test/golden/Fixities.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test/Fail/Fixities.agda:6,1-6
Invalid fixity 8.5 for operator _<+>_
8 changes: 8 additions & 0 deletions test/golden/Fixities.hs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,11 @@ nonAssoc b = (b == b) == (b == b)
mixedAssoc :: Maybe Int -> (Int -> Maybe Int) -> Maybe Int
mixedAssoc m f = f =<< ((f =<< m) >>= f >>= f)

infixl 7 <+>
(<+>) :: Int -> Int -> Int
x <+> y = x + y

infixr 8 <->
(<->) :: Int -> Int -> Int
x <-> y = x - y

0 comments on commit 13efde6

Please sign in to comment.