@@ -6,6 +6,7 @@ import Control.Alternative (guard)
66import Data.Array as Array
77import Data.Array.NonEmpty (NonEmptyArray)
88import Data.Array.NonEmpty as NonEmptyArray
9+import Data.Either (Either(..))
910import Data.Foldable (class Foldable, and, foldMap, foldl, foldr, or)
1011import Data.Foldable as Foldable
1112import Data.Foldable as Tuple
@@ -45,6 +46,7 @@ data BackendSemantics
4546 | SemEffectPure BackendSemantics
4647 | SemEffectDefer BackendSemantics
4748 | SemBranch (NonEmptyArray (SemConditional BackendSemantics)) (Lazy BackendSemantics)
49+ | SemAssocOp (Either (Qualified Ident) BackendOperator2) (NonEmptyArray BackendSemantics)
4850 | NeutLocal (Maybe Ident) Level
4951 | NeutVar (Qualified Ident)
5052 | NeutStop (Qualified Ident)
@@ -733,8 +735,9 @@ evalPrimOp env = case _ of
733735 , NeutLit (LitString b) <- deref y ->
734736 liftBoolean (evalPrimOpOrd op a b)
735737 OpStringAppend
736− | Just result <- evalPrimOpAssocL OpStringAppend caseString (\a b -> Just $ liftString (a <> b)) x y ->
737− result
738+ | NeutLit (LitString a) <- x
739+ , NeutLit (LitString b) <- y ->
740+ liftString (a <> b)
738741 OpArrayIndex
739742 | NeutLit (LitInt n) <- y ->
740743 evalAccessor env x (GetIndex n)
@@ -756,43 +759,10 @@ evalPrimOp env = case _ of
756759 _, NeutFail err -> NeutFail err
757760 _, _ ->
758761 evalAssocLet2 env x y \_ x' y' ->
759− NeutPrimOp (Op2 op2 x' y')
760−
761−evalPrimOpAssocL :: forall a. BackendOperator2 -> (BackendSemantics -> Maybe a) -> (a -> a -> Maybe BackendSemantics) -> BackendSemantics -> BackendSemantics -> Maybe BackendSemantics
762−evalPrimOpAssocL op match combine a b = case match a of
763− Just lhs
764− | Just rhs <- match b ->
765− combine lhs rhs
766− | Just (Tuple x y) <- decompose b ->
767− case match x of
768− Just rhs ->
769− (\x' -> liftOp2 op x' y) <$> combine lhs rhs
770− Nothing
771− | Just (Tuple v w) <- decompose x
772− , Just rhs <- match v ->
773− (\v' -> liftOp2 op (liftOp2 op v' w) y) <$> combine lhs rhs
774− _ ->
775− Nothing
776− Nothing
777− | Just rhs <- match b
778− , Just (Tuple v w) <- decompose a ->
779− case match w of
780− Just lhs ->
781− liftOp2 op v <$> combine lhs rhs
782− Nothing
783− | Just (Tuple x y) <- decompose w
784− , Just lhs <- match y ->
785− liftOp2 op (liftOp2 op v x) <$> combine lhs rhs
786− _ ->
787− Nothing
788− _ ->
789− Nothing
790− where
791− decompose = case _ of
792− NeutPrimOp (Op2 op' x y) | op == op' ->
793− Just (Tuple x y)
794− _ ->
795− Nothing
762+ if isAssocPrimOp op2 then
763+ evalAssocOp env (Right op2) x' y'
764+ else
765+ NeutPrimOp (Op2 op2 x' y')
796766
797767evalPrimOpOrd :: forall a. Ord a => BackendOperatorOrd -> a -> a -> Boolean
798768evalPrimOpOrd op x y = case op of
@@ -815,56 +785,38 @@ evalPrimOpOrdNumber op x y = case op of
815785 OpLte -> x <= y
816786
817787evalPrimOpNumNumber :: BackendOperatorNum -> BackendSemantics -> BackendSemantics -> Maybe BackendSemantics
818−evalPrimOpNumNumber op x y = case op of
819− OpAdd ->
820− evalPrimOpAssocL (OpNumberNum OpAdd) (caseNumber <<< deref) (\a b -> Just $ liftNumber (a + b)) x y
821− OpMultiply ->
822− evalPrimOpAssocL (OpNumberNum OpMultiply) (caseNumber <<< deref) (\a b -> Just $ liftNumber (a * b)) x y
823− OpSubtract
824− | NeutLit (LitNumber a) <- deref x
825− , NeutLit (LitNumber b) <- deref y ->
826− Just $ liftNumber (a - b)
827− OpDivide
828− | NeutLit (LitNumber a) <- deref x
829− , NeutLit (LitNumber b) <- deref y ->
830− Just $ liftNumber (a / b)
831− _ ->
832− Nothing
788+evalPrimOpNumNumber op x y
789+ | NeutLit (LitNumber a) <- deref x
790+ , NeutLit (LitNumber b) <- deref y =
791+ Just $ liftNumber case op of
792+ OpAdd -> a + b
793+ OpMultiply -> a * b
794+ OpSubtract -> a - b
795+ OpDivide -> a / b
796+ | otherwise =
797+ Nothing
833798
834799evalPrimOpNumInt :: BackendOperatorNum -> BackendSemantics -> BackendSemantics -> Maybe BackendSemantics
835−evalPrimOpNumInt op x y = case op of
836− OpAdd ->
837− evalPrimOpAssocL (OpIntNum OpAdd) (caseInt <<< deref) addOverflow x y
838− where
839− addOverflow a b = do
840− let res = a + b
841− if b > 0 && res < a || b < 0 && res > a then
842− Nothing
843− else
844− Just $ liftInt res
845− OpMultiply ->
846− evalPrimOpAssocL (OpIntNum OpMultiply) (caseInt <<< deref) mulOverflow x y
847− where
848− mulOverflow a b = do
849− let res = a * b
850− if a /= (res / b) then
851− Nothing
852− else
853− Just $ liftInt res
854− OpSubtract
855− | NeutLit (LitInt a) <- deref x
856− , NeutLit (LitInt b) <- deref y -> do
857− let res = a - b
858− if b > 0 && res > a || b < 0 && res < a then
859− Nothing
860− else
861− Just $ liftInt res
862− OpDivide
863− | NeutLit (LitInt a) <- deref x
864− , NeutLit (LitInt b) <- deref y ->
865− Just $ liftInt (a / b)
866− _ ->
867− Nothing
800+evalPrimOpNumInt op x y
801+ | NeutLit (LitInt a) <- deref x
802+ , NeutLit (LitInt b) <- deref y =
803+ case op of
804+ OpAdd -> do
805+ let res = a + b
806+ if b > 0 && res < a || b < 0 && res > a then Nothing
807+ else Just $ liftInt res
808+ OpMultiply -> do
809+ let res = a * b
810+ if a /= (res / b) then Nothing
811+ else Just $ liftInt res
812+ OpSubtract -> do
813+ let res = a - b
814+ if b > 0 && res > a || b < 0 && res < a then Nothing
815+ else Just $ liftInt res
816+ OpDivide ->
817+ Just $ liftInt (a / b)
818+ | otherwise =
819+ Nothing
868820
869821evalPrimOpNot :: BackendOperator BackendSemantics -> BackendSemantics
870822evalPrimOpNot = case _ of
@@ -898,6 +850,56 @@ primOpOrdNot = case _ of
898850 OpGt -> OpLte
899851 OpGte -> OpLt
900852
853+isAssocPrimOp :: BackendOperator2 -> Boolean
854+isAssocPrimOp = case _ of
855+ OpIntNum OpAdd -> true
856+ OpIntNum OpMultiply -> true
857+ OpNumberNum OpAdd -> true
858+ OpNumberNum OpMultiply -> true
859+ OpStringAppend -> true
860+ _ -> false
861+
862+evalAssocOp :: Env -> Either (Qualified Ident) BackendOperator2 -> BackendSemantics -> BackendSemantics -> BackendSemantics
863+evalAssocOp env op1 = case _, _ of
864+ SemAssocOp op2 as, SemAssocOp op3 bs
865+ | op1 == op2
866+ , op2 == op3 ->
867+ case evalAssocOp' env op1 (NonEmptyArray.last as) (NonEmptyArray.head bs) of
868+ SemAssocOp op4 cs
869+ | op3 == op4 ->
870+ SemAssocOp op1 $ NonEmptyArray.prependArray (NonEmptyArray.init as) (NonEmptyArray.appendArray cs (NonEmptyArray.tail bs))
871+ c ->
872+ SemAssocOp op1 $ NonEmptyArray.prependArray (NonEmptyArray.init as) (NonEmptyArray.cons' c (NonEmptyArray.tail bs))
873+ a, SemAssocOp op2 bs
874+ | op1 == op2 ->
875+ case evalAssocOp' env op1 a (NonEmptyArray.head bs) of
876+ SemAssocOp op3 cs
877+ | op2 == op3 ->
878+ SemAssocOp op1 $ NonEmptyArray.appendArray cs (NonEmptyArray.tail bs)
879+ a' ->
880+ SemAssocOp op1 $ NonEmptyArray.cons' a' (NonEmptyArray.tail bs)
881+ SemAssocOp op2 as, b
882+ | op1 == op2 ->
883+ case evalAssocOp' env op1 (NonEmptyArray.last as) b of
884+ SemAssocOp op3 cs
885+ | op2 == op3 ->
886+ SemAssocOp op1 $ NonEmptyArray.prependArray (NonEmptyArray.init as) cs
887+ b' ->
888+ SemAssocOp op1 $ NonEmptyArray.snoc' (NonEmptyArray.init as) b'
889+ a, b ->
890+ SemAssocOp op1 $ NonEmptyArray.cons' a [ b ]
891+
892+evalAssocOp' :: Env -> Either (Qualified Ident) BackendOperator2 -> BackendSemantics -> BackendSemantics -> BackendSemantics
893+evalAssocOp' env@(Env e) op a b = case op of
894+ Left qual ->
895+ case e.evalExternSpine env qual [ ExternApp [ a, b ] ] of
896+ Just res ->
897+ res
898+ Nothing ->
899+ SemAssocOp op $ NonEmptyArray.cons' a [ b ]
900+ Right primOp ->
901+ evalPrimOp env (Op2 primOp a b)
902+
901903evalRef :: Env -> EvalRef -> Array ExternSpine -> ExternSpine -> Lazy BackendSemantics -> BackendSemantics
902904evalRef env@(Env e) ref spine last sem = case ref of
903905 EvalExtern qual
@@ -1214,6 +1216,16 @@ quote = go
12141216 MkFnApplied body ->
12151217 build ctx' $ UncurriedEffectAbs idents $ quote (ctx' { effect = false }) body
12161218 loop ctx [] pro
1219+ SemAssocOp op spine ->
1220+ foldl1Array
1221+ ( \a b -> case op of
1222+ Left qual ->
1223+ build ctx $ App (build ctx (Var qual)) $ NonEmptyArray.cons' a [ quote ctx b ]
1224+ Right primOp ->
1225+ build ctx $ PrimOp (Op2 primOp a (quote ctx b))
1226+ )
1227+ (quote ctx)
1228+ spine
12171229 NeutLocal ident level ->
12181230 build ctx $ Local ident level
12191231 NeutVar qual ->