implementation module commondef import StdArray, StdBool, StdChar, StdClass, StdEnum, StdFunc, StdInt, StdList, StdMisc, StdReal, StdString import osrgn import StdIOCommon /* Extensions of StdFunc: */ k` :: .x !.y -> .y k` _ y = y /* Calculation rules on Integers: */ dist :: !Int !Int -> Int dist x y = abs (x-y) setBetween :: !Int !Int !Int -> Int setBetween x low up | x<=low = low | x>=up = up | otherwise = x setBetweenCheckBounds :: !Int !Int !Int -> Int setBetweenCheckBounds x low up | up <= low = low | x<=low = low | x>=up = up | otherwise = x isBetween :: !Int !Int !Int -> Bool isBetween x low up | x (!Int,!Int) minmax a b | a<=b = (a,b) | otherwise = (b,a) /* Calculation rules on Points, Sizes, and Vectors: */ addPointSize :: !Size !Point2 -> Point2 addPointSize {w,h} {x,y} = {x=x+w,y=y+h} instance zero OSRect where zero = {rleft=0,rtop=0,rright=0,rbottom=0} instance == OSRect where (==) r1 r2 = r1.rleft==r2.rleft && r1.rtop==r2.rtop && r1.rright==r2.rright && r1.rbottom==r2.rbottom class addVector a :: !Vector2 !a -> a // add the vector argument to the second argument instance addVector Point2 where addVector {vx,vy} {x,y} = {x=x+vx,y=y+vy} instance addVector OSRect where addVector {vx,vy} {rleft,rtop,rright,rbottom} = {rleft=rleft+vx,rtop=rtop+vy,rright=rright+vx,rbottom=rbottom+vy} instance addVector Rectangle where addVector v {corner1,corner2} = {corner1=addVector v corner1,corner2=addVector v corner2} class subVector a :: !Vector2 !a -> a // subtract the vector argument from the second argument instance subVector Point2 where subVector {vx,vy} {x,y} = {x=x-vx,y=y-vy} instance subVector OSRect where subVector {vx,vy} {rleft,rtop,rright,rbottom} = {rleft=rleft-vx,rtop=rtop-vy,rright=rright-vx,rbottom=rbottom-vy} instance subVector Rectangle where subVector v {corner1,corner2} = {corner1=subVector v corner1,corner2=subVector v corner2} rectangleToRect :: !Rectangle -> OSRect rectangleToRect {corner1={x=a,y=b},corner2={x=a`,y=b`}} | x_less_x` && y_less_y`= {rleft=a, rtop=b, rright=a`,rbottom=b`} | x_less_x` = {rleft=a, rtop=b`,rright=a`,rbottom=b } | y_less_y` = {rleft=a`,rtop=b, rright=a, rbottom=b`} | otherwise = {rleft=a`,rtop=b`,rright=a, rbottom=b } where x_less_x` = a<=a` y_less_y` = b<=b` rectToRectangle :: !OSRect -> Rectangle rectToRectangle {rleft,rtop,rright,rbottom} = {corner1={x=rleft,y=rtop},corner2={x=rright,y=rbottom}} isEmptyRect :: !OSRect -> Bool isEmptyRect {rleft,rtop,rright,rbottom} = rleft==rright || rtop==rbottom isEmptyRectangle :: !Rectangle -> Bool isEmptyRectangle {corner1,corner2} = corner1.x==corner2.x || corner1.y==corner2.y pointInRect :: !Point2 !OSRect -> Bool pointInRect {x,y} {rleft,rtop,rright,rbottom} = isBetween x rleft rright && isBetween y rtop rbottom pointInRectangle :: !Point2 !Rectangle -> Bool pointInRectangle point rectangle = pointInRect point (rectangleToRect rectangle) posSizeToRect :: !Point2 !Size -> OSRect posSizeToRect {x,y} {w,h} = {rleft=left,rtop=top, rright=right,rbottom=bottom} where (left,right) = minmax x (x+w) (top,bottom) = minmax y (y+h) posSizeToRectangle :: !Point2 !Size -> Rectangle posSizeToRectangle pos=:{x,y} {w,h} = {corner1=pos,corner2={x=x+w,y=y+h}} sizeToRect :: !Size -> OSRect sizeToRect size = posSizeToRect zero size sizeToRectangle :: !Size -> Rectangle sizeToRectangle {w,h} = {zero & corner2={x=w,y=h}} disjointRects :: !OSRect !OSRect -> Bool disjointRects rect1 rect2 = isEmptyRect rect1 || isEmptyRect rect2 || rect1.rleft>=rect2.rright || rect1.rbottom<=rect2.rtop || rect1.rright<=rect2.rleft || rect1.rtop>=rect2.rbottom intersectRects :: !OSRect !OSRect -> OSRect intersectRects rect1 rect2 | disjointRects rect1 rect2 = zero | otherwise = { rleft = max rect1.rleft rect2.rleft , rtop = max rect1.rtop rect2.rtop , rright = min rect1.rright rect2.rright , rbottom = min rect1.rbottom rect2.rbottom } subtractRects :: !OSRect !OSRect -> [OSRect] subtractRects rect1 rect2 = subtractFittingRect rect1 (intersectRects rect1 rect2) where // subtractFittingRect r1 r2 subtracts r2 from r1 assuming that r2 fits inside r1 subtractFittingRect :: !OSRect !OSRect -> [OSRect] subtractFittingRect {rleft=l1,rtop=t1,rright=r1,rbottom=b1} {rleft=l2,rtop=t2,rright=r2,rbottom=b2} = filter (not o isEmptyRect) (map fromTuple4 [(l1,t1,r1,t2),(l1,t2,l2,b2),(r2,t2,r1,b2),(l1,b2,r1,b1)]) rectSize :: !OSRect -> Size rectSize {rleft,rtop,rright,rbottom} = {w=abs (rright-rleft),h=abs (rbottom-rtop)} /* Rules on RgnHandles and Rects: */ intersectRgnRect :: !OSRgnHandle !OSRect !*OSToolbox -> (!OSRgnHandle,!*OSToolbox) intersectRgnRect rgnH rect tb # (aidRgn,tb) = osnewrectrgn rect tb # (secRgn,tb) = ossectrgn rgnH aidRgn tb # tb = osdisposergn aidRgn tb = (secRgn,tb) /* PA: Conversion of Size, Point2, and Vector2 to tuples (toTuple) and from tuples (fromTuple): */ class toTuple a :: !a -> (!Int,!Int) class fromTuple a :: !(!Int,!Int) -> a instance toTuple Size where toTuple {w,h} = (w,h) instance toTuple Point2 where toTuple {x,y} = (x,y) instance toTuple Vector2 where toTuple {vx,vy} = (vx,vy) instance fromTuple Size where fromTuple (w,h) = {w=w,h=h} instance fromTuple Point2 where fromTuple (x,y) = {x=x,y=y} instance fromTuple Vector2 where fromTuple (vx,vy) = {vx=vx,vy=vy} /* PA: Conversion of OSRect, and Rectangle to 4-tuples (toTuple4) and from 4-tuples (fromTuple4): */ class toTuple4 a :: !a -> (!Int,!Int,!Int,!Int) class fromTuple4 a :: !(!Int,!Int,!Int,!Int) -> a instance toTuple4 OSRect where toTuple4 {rleft,rtop,rright,rbottom} = (rleft,rtop,rright,rbottom) instance toTuple4 Rectangle where toTuple4 r = toTuple4 (rectangleToRect r) instance fromTuple4 OSRect where fromTuple4 r = rectangleToRect (fromTuple4 r) instance fromTuple4 Rectangle where fromTuple4 (l,t,r,b) = {corner1={x=l,y=t},corner2={x=r,y=b}} /* Tuple functions: */ swap :: !(.a,.b) -> (.b,.a) swap (a,b) = (b,a) /* Error generation rule: */ error :: !String !String !String -> .x error rule moduleName error = abort ("Error in rule "+++rule+++" ["+++moduleName+++"]: "+++error+++".\n") // PA: new version of error to dump fatal errors. fatalError :: !String !String !String -> .x fatalError rule moduleName error = abort ("Fatal error in rule "+++rule+++" ["+++moduleName+++"]: "+++error+++".\n") /* Universal dummy value (!!evaluation causes termination with the message: "Fatal error: dummy evaluated!"!!) */ dummy :: !String -> .x dummy error = abort ("Fatal error: dummy evaluated! "+++error+++".\n") /* Max Integer constants: */ MaxSigned2ByteInt :== 32767 // 2^15-1 MaxSigned4ByteInt :== 2147483647 // 2^31-1 /* Bound data type: */ :: Bound = Finite Int // Fix a finite positive bound of N | Infinite // No bound instance == Bound where (==) (Finite i) (Finite j) = i==j || i<=0 && j<=0 (==) Infinite Infinite = True (==) _ _ = False zeroBound:: !Bound -> Bool zeroBound (Finite i) = i<=0 zeroBound _ = False decBound :: !Bound -> Bound decBound (Finite i) | i<=0 = Finite 0 | otherwise = Finite (i-1) decBound bound = bound incBound :: !Bound -> Bound incBound (Finite i) | i<=0 = Finite 1 | otherwise = Finite (i+1) incBound bound = bound /* List operations: */ :: Cond x :== x -> Bool :: UCond x :== x -> *(Bool,x) (orc) infixr 2 :: !(Cond x) (Cond x) x -> Bool (orc) ca cb x = ca x || cb x (andc) infixr 3 :: !(Cond x) (Cond x) x -> Bool (andc) ca cb x = ca x && cb x uisEmpty :: !v:[u:x] -> (!Bool,!v:[u:x]), [v<=u] uisEmpty [] = (True,[]) uisEmpty full = (False,full) isSingleton :: ![.x] -> Bool isSingleton [x] = True isSingleton _ = False hdtl :: !u:[.x] -> (!.x, !u:[.x]) hdtl [x:xs] = (x,xs) initLast :: ![.x] -> (![.x],!.x) initLast [x] = ([],x) initLast [x:xs] # (init,last) = initLast xs = ([x:init],last) split :: !Int !u:[.x] -> (![.x],!u:[.x]) split _ [] = ([],[]) split n xs | n<=0 = ([],xs) | otherwise # (x, xs) = hdtl xs # (ys,zs) = split (n-1) xs = ([x:ys],zs) condMap :: (Cond x) !(IdFun x) ![x] -> (!Bool,![x]) condMap c f [x:xs] # (b,xs) = condMap c f xs | c x = (True,[f x:xs]) | otherwise = (b, [x:xs]) condMap _ _ _ = (False,[]) uspan :: !(UCond .a) !u:[.a] -> (![.a],!u:[.a]) // Same as span (StdList), but preserving uniqueness uspan c [x:xs] # (keep,x) = c x | keep = ([x:ys],zs) with (ys,zs) = uspan c xs | otherwise = ([],[x:xs]) uspan _ _ = ([],[]) filterMap :: !(.x -> *(Bool,.y)) ![.x] -> [.y] filterMap f [x:xs] #! (keep,y) = f x #! ys = filterMap f xs | keep = [y:ys] | otherwise = ys filterMap _ _ = [] stateMap :: !(u:x -> v:(.s -> (.y,.s))) ![u:x] !.s -> (![.y],!.s), [v<=u] stateMap f [x:xs] s #! (y, s) = f x s #! (ys,s) = stateMap f xs s = ([y:ys],s) stateMap _ _ s = ([],s) stateMap2 :: !(u:x -> .(.s -> .s)) !v:[u:x] !.s -> .s, [v <= u] stateMap2 f [x:xs] s = stateMap2 f xs (f x s) stateMap2 _ _ s = s strictSeq :: ![.(.s -> .s)] !.s -> .s // Same as seq (StdFunc), but with strict state argument strictSeq [f:fs] s = strictSeq fs (f s) strictSeq _ s = s strictSeqList :: !.[.St .s .x] !.s -> (![.x],!.s) // Same as seqList (StdFunc), but with strict state argument strictSeqList [f:fs] s # (x, s) = f s # (xs,s) = strictSeqList fs s = ([x:xs],s) strictSeqList _ s = ([],s) allList :: !(.x .s -> .(Bool,.s)) ![.x] !.s -> (!Bool,!.s) allList cond [x:xs] s # (ok,s) = cond x s | ok = allList cond xs s | otherwise = (False,s) allList _ _ s = (True,s) contains :: !(Cond x) ![x] -> Bool contains c [x:xs] = c x || contains c xs contains _ _ = False ucontains :: !(UCond .x) !u:[.x] -> (!Bool,!u:[.x]) ucontains c [x:xs] # (cond,x) = c x | cond = (True,[x:xs]) | otherwise # (b,xs) = ucontains c xs = (b,[x:xs]) ucontains _ [] = (False,[]) cselect :: !(Cond x) x ![x] -> (!Bool, x) cselect c n [x:xs] | c x = (True,x) | otherwise = cselect c n xs cselect _ n _ = (False,n) ucselect :: !(Cond x) x !u:[ x] -> (!Bool, x,!u:[x]) ucselect c n [x:xs] | c x = (True,x,[x:xs]) | otherwise # (found,y,xs) = ucselect c n xs = (found,y,[x:xs]) ucselect _ n [] = (False,n,[]) selectedAtIndex :: !(Cond x) x ![x] -> (!Index, x) selectedAtIndex cond dummy xs = (if found i 0,x) where (found,i,x) = selected cond dummy xs 1 selected :: (Cond x) x ![x] !Int -> (!Bool,!Int,x) selected cond dummy [x:xs] i | cond x = (True,i,x) | otherwise = selected cond dummy xs (i+1) selected _ dummy _ i = (False,i,dummy) access :: !(St .x *(Bool,.y)) .y !u:[.x] -> (!Bool,.y,!u:[.x]) access acc n [x:xs] # ((cond,y),x) = acc x | cond = (True,y,[x:xs]) | otherwise # (b,y,xs) = access acc n xs = (b,y,[x:xs]) access _ n [] = (False,n,[]) accessList :: !(St .x .y) ![.x] -> (![.y],![.x]) accessList acc [x:xs] #! (y, x) = acc x #! (ys,xs) = accessList acc xs = ([y:ys],[x:xs]) accessList _ [] = ([],[]) remove :: !(Cond x) x !u:[x] -> (!Bool,x,!u:[x]) remove c n [x:xs] | c x = (True,x,xs) | otherwise # (b,y,xs) = remove c n xs = (b,y,[x:xs]) remove _ n _ = (False,n,[]) uremove :: !(UCond .x) .x !u:[.x] -> (!Bool,.x,!u:[.x]) uremove c n [x:xs] # (cond,x) = c x | cond = (True,x,xs) | otherwise # (b,y,xs) = uremove c n xs = (b,y,[x:xs]) uremove _ n [] = (False,n,[]) creplace :: !(Cond x) x ![x] -> (!Bool,![x]) creplace c y [x:xs] | c x = (True,[y:xs]) | otherwise # (b,xs) = creplace c y xs = (b,[x:xs]) creplace _ _ _ = (False,[]) ucreplace :: !(UCond .x) .x !u:[.x] -> (!Bool,!u:[.x]) ucreplace c y [x:xs] # (cond,x)= c x | cond = (True,[y:xs]) | otherwise # (b,xs) = ucreplace c y xs = (b,[x:xs]) ucreplace _ _ [] = (False,[]) replaceOrAppend :: !(Cond x) x ![x] -> [x] replaceOrAppend c y [x:xs] | c x = [y:xs] | otherwise = [x:replaceOrAppend c y xs] replaceOrAppend _ y _ = [y] ureplaceOrAppend :: !(UCond .x) .x !u:[.x] -> u:[.x] ureplaceOrAppend c y [x:xs] # (cond,x)= c x | cond = [y:xs] | otherwise = [x:ureplaceOrAppend c y xs] ureplaceOrAppend _ y _ = [y] ulength :: ![.x] -> (!Int,![.x]) ulength [x:xs] # (length,xs)= ulength xs = (length+1,[x:xs]) ulength _ = (0,[]) removeCheck :: x !u:[x] -> (!Bool, !u:[x]) | Eq x removeCheck y [x:xs] | y==x = (True,xs) | otherwise # (b,xs) = removeCheck y xs = (b,[x:xs]) removeCheck _ _ = (False,[]) removeSpecialChars :: ![Char] !{#Char} -> {#Char} removeSpecialChars sc string = {c\\c<-removeSpecialChars` sc [c\\c<-:string]} where removeSpecialChars` :: ![Char] ![Char] -> [Char] removeSpecialChars` sc [c1:cs1=:[c2:cs2]] | isMember c1 sc = [c2:removeSpecialChars` sc cs2] | otherwise = [c1:removeSpecialChars` sc cs1] removeSpecialChars` sc [c] | isMember c sc = [] | otherwise = [c] removeSpecialChars` _ _ = [] disjointLists :: ![x] ![x] -> Bool | Eq x disjointLists xs ys | isEmpty xs || isEmpty ys = True | shorter xs ys = disjointLists` xs ys | otherwise = disjointLists` ys xs where shorter :: ![x] ![x] -> Bool shorter [] _ = True shorter [x:xs] [y:ys] = shorter xs ys shorter _ _ = False disjointLists` :: ![x] ![x] -> Bool | Eq x disjointLists` [x:xs] ys = not (isMember x ys) && disjointLists` xs ys disjointLists` _ _ = True noDuplicates :: ![x] -> Bool | Eq x noDuplicates [x:xs] = not (isMember x xs) && noDuplicates xs noDuplicates _ = True unzip3 :: ![(.a,.b,.c)] -> (![.a],![.b],![.c]) unzip3 [(a,b,c):abcs] #! (as,bs,cs) = unzip3 abcs = ([a:as],[b:bs],[c:cs]) unzip3 [] = ([],[],[]) unzip4 :: ![(.a,.b,.c,.d)] -> (![.a],![.b],![.c],![.d]) unzip4 [(a,b,c,d):abcds] #! (as,bs,cs,ds) = unzip4 abcds = ([a:as],[b:bs],[c:cs],[d:ds]) unzip4 [] = ([],[],[],[])