implementation module StdIOBasic


import	StdBool, StdInt, StdList, StdOverloaded, StdString
from	commondef	import error


/*	General type constructors for composing context-independent data structures.
*/
::	:^:		t1 t2			= (:^:) infixr 9 t1 t2


/*	General type constructors for composing context-dependent data structures.
*/
::	:~:		t1 t2		cs	= (:~:) infixr 9 (t1 cs) (t2 cs)
::	ListCS	t			cs	= ListCS .[t cs]
::	NilCS				cs	= NilCS


/*	General type constructors for composing local and context-dependent 
	data structures.
*/
::	:+:		t1 t2	ls	cs	= (:+:) infixr 9 (t1 ls cs) (t2 ls cs)
::	ListLS		t	ls	cs	= ListLS .[t ls cs]
::	NilLS			ls	cs	= NilLS
::	NewLS		t	ls	cs	= E. .new: {newLS :: new, newDef :: t   new		cs}
::	AddLS		t	ls	cs	= E. .add: {addLS :: add, addDef :: t *(add,ls)	cs}

noLS :: (.a->.b) !(.c,.a) -> (.c,.b)
noLS f (c,a) = (c,f a)

noLS1:: (.x->.a->.b) .x !(.c,.a) -> (.c,.b)
noLS1 f x (c,a) = (c,f x a)


/*	Frequently occurring data types.					*/

::	Index				:==	Int
::	Title				:==	String
::	Size
	=	{	w			:: !Int
		,	h			:: !Int
		}
::	Vector2
	=	{	vx			:: !Int
		,	vy			:: !Int
		}
::	Point2
	=	{	x			:: !Int
		,	y			:: !Int
		}
::	Rectangle
	=	{	corner1		:: !Point2
		,	corner2		:: !Point2
		}

class toVector x :: !x -> Vector2


instance == Size where
	(==) {w=a,h=b} {w=c,h=d} = a==c && b==d
instance zero Size where
	zero = {w=0,h=0}
instance toVector Size where
	toVector {w,h} = {vx=w,vy=h}
instance toString Size where
	toString {w,h}
		= curlify (itemsList "," (map recordFieldtoString (zip2 ["w","h"] [w,h])))


instance == Vector2 where
	(==) {vx=a,vy=b} {vx=c,vy=d} = a==c && b==d
instance + Vector2 where
	(+) {vx=vx1,vy=vy1} {vx=vx2,vy=vy2} = {vx=vx1+vx2,vy=vy1+vy2}
instance - Vector2 where
	(-) {vx=vx1,vy=vy1} {vx=vx2,vy=vy2} = {vx=vx1-vx2,vy=vy1-vy2}
instance zero Vector2 where
	zero = {vx=0,vy=0}
instance ~ Vector2 where
	(~) {vx,vy} = {vx=0-vx,vy=0-vy}
instance toString Vector2 where
	toString {vx,vy}
		= curlify (itemsList "," (map recordFieldtoString (zip2 ["vx","vy"] [vx,vy])))


instance == Point2 where
	(==) {x=a,y=b} {x=c,y=d} = a==c && b==d
instance + Point2 where
	(+) {x=x1,y=y1} {x=x2,y=y2} = {x=x1+x2,y=y1+y2}
instance - Point2 where
	(-) {x=x1,y=y1} {x=x2,y=y2} = {x=x1-x2,y=y1-y2}
instance zero Point2 where
	zero = {x=0,y=0}
instance ~ Point2 where
	(~) {x,y} = {x=0-x,y=0-y}
instance toVector Point2 where
	toVector {x,y}
		= {vx=x,vy=y}
instance toString Point2 where
	toString {x,y}
		= curlify (itemsList "," (map recordFieldtoString (zip2 ["x","y"] [x,y])))

movePoint :: !Vector2 !Point2 -> .Point2
movePoint {vx,vy} {x,y} = {x=vx+x,y=vy+y}


instance == Rectangle where
	(==) {corner1=a,corner2=b} {corner1=c,corner2=d} = a==c && b==d
instance zero Rectangle where
	zero = {corner1=zero,corner2=zero}
instance toString Rectangle where
	toString {corner1,corner2}
		= curlify (itemsList "," (map recordFieldtoString (zip2 ["corner1","corner2"] [corner1,corner2])))

rectangleSize :: !Rectangle -> Size
rectangleSize {corner1={x=x1,y=y1},corner2={x=x2,y=y2}}
	= {w=abs (x2-x1),h=abs (y2-y1)}


::	IdFun st
	:==	st -> st


//	Some handy functions for toString:
curlify  x = "{"+++x+++"}"

recordFieldtoString :: (String,a) -> String | toString a	// recordFieldtoString f v -> f=v
recordFieldtoString (field,value) = field+++"="+++toString value

itemsList :: !String ![String] -> String	// itemsList c [a0,...an] -> a0 c a1 c ... c an
itemsList separator [x:xs]
	= x+++itemsList` xs
where
	itemsList` [x:xs]	= separator+++x+++itemsList` xs
	itemsList` _		= ""
itemsList _ _
	= ""

::	Void
 =	Void // MW11++


::	Alt2 a b = Alt1Of2 a | Alt2Of2 b	// Alternative data type in cases where Either causes name clashes

alt1Of2 :: !(Alt2 a b) -> a				// Take first  alternative if applicable (test with isAlt1Of2)
alt1Of2 (Alt1Of2 a)	= a
alt1Of2 _			= error "alt1Of2" "StdIOBasic" "argument is (Alt2Of2 _) instead of (Alt1Of2 _)"

alt2Of2 :: !(Alt2 a b) -> b				// Take second alternative if applicable (test with isAlt2Of2)
alt2Of2 (Alt2Of2 b)	= b
alt2Of2 _			= error "alt2Of2" "StdIOBasic" "argument is (Alt1Of2 _) instead of (Alt2Of2 _)"

isAlt1Of2 :: !(Alt2 a b) -> Bool		// True iff (Alt1Of2 _)
isAlt1Of2 (Alt1Of2 _)	= True
isAlt1Of2 _				= False

isAlt2Of2 :: !(Alt2 a b) -> Bool		// True iff (Alt2Of2 _)
isAlt2Of2 (Alt2Of2 _)	= True
isAlt2Of2 _				= False
