[M3devel] mixing INTEGER and LONGINT?
Randy Coleburn
rcolebur at SCIRES.COM
Fri Jan 8 18:36:50 CET 2010
I agree with Tony that we need a clean proposal to debate. I also agree with keeping the spirit of the Modula-3 language and type rules.
Randy Coleburn
-----Original Message-----
From: Tony Hosking [mailto:hosking at cs.purdue.edu]
Sent: Friday, January 08, 2010 12:00 PM
To: Jay K
Cc: m3devel
Subject: Re: [M3devel] mixing INTEGER and LONGINT?
Let's have a clean language proposal before thinking about implementing it... ;-)
I continue to oppose mixing operations on both LONGINT and INTEGER. Just as one cannot mix REAL and LONGREAL.
I may accept checked assignability between INTEGER and LONGINT (after all, the bits are the same, its just a matter of how many are significant -- unlike REAL/LONGREAL/EXTENDED).
Looking further at the assignability rules:
A type T is assignable to a type U if:
* T <: U, or
* U <: T and T is an array or a reference type other than ADDRESS (This restriction is lifted in unsafe modules.), or
* T and U are ordinal types with at least one member in common.
This suggests that we don't really need to say that INTEGER <: LONGINT.
We can simply rely on the third clause regarding their both being ordinal types with at least one member in common. Then assignment simply needs to test that the values are in range.
On 8 Jan 2010, at 02:44, Jay K wrote:
> This simple diff in the front end allows the "obvious" mixing of INTEGER and LONGINT without any need for ORD or VAL.
>
> LONGINT + INTEGER => LONGINT
> LONGINT - INTEGER => LONGINT
> LONGINT * INTEGER => LONGINT
> LONGINT DIV INTEGER => LONGINT
> INTEGER DIV LONGINT => LONGINT (subtle and I think incorrect, should be INTEGER)
> INTEGER MOD LONGINT => INTEGER (subtle but I believe correct)
> LONGINT MOD INTEGER => INTEGER (subtle but I believe correct)
> MIN(INTEGER, LONGINT) => LONGINT (This is wrong actually, should be INTEGER)
> MAX(INTEGER, LONGINT) => LONGINT
> LONGINT := INTEGER
>
> Other mixes are less obvious and would require runtime checks.
>
> I think the backend will just work but I haven't tried that yet.
> (Truth be told, I can only affectively edit files on NT...)
>
> Thoughts?
>
> - Jay
>
> Index: builtinOps/Dec.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/builtinOps/Dec.m3,v
> retrieving revision 1.9
> diff -u -r1.9 Dec.m3
> --- builtinOps/Dec.m3 25 Sep 2009 02:42:10 -0000 1.9
> +++ builtinOps/Dec.m3 8 Jan 2010 07:35:43 -0000
> @@ -44,7 +44,7 @@
> IF (NUMBER (ce.args^) > 1) THEN
> IF Type.IsSubtype (t, LInt.T) THEN
> t := Type.Base (Expr.TypeOf (ce.args[1]));
> - IF (t # LInt.T) THEN
> + IF t # LInt.T AND t # Int.T THEN
> Error.Txt (name, "second argument must be a LONGINT");
> END;
> ELSE
> Index: builtinOps/Max.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/builtinOps/Max.m3,v
> retrieving revision 1.3
> diff -u -r1.3 Max.m3
> --- builtinOps/Max.m3 18 Sep 2007 20:25:36 -0000 1.3
> +++ builtinOps/Max.m3 8 Jan 2010 07:35:43 -0000
> @@ -25,11 +25,14 @@
>
> PROCEDURE DoCheck (name: TEXT; ce: CallExpr.T) =
> VAR ta, tb: Type.T;
> + resultType: Type.T := NIL;
> BEGIN
> ta := Type.Base (Expr.TypeOf (ce.args[0]));
> tb := Type.Base (Expr.TypeOf (ce.args[1]));
>
> - IF (NOT Type.IsEqual (ta, tb, NIL)) THEN
> + IF (ta = LInt.T AND tb = Int.T) OR (tb = LInt.T AND ta = Int.T) THEN
> + resultType := LInt.T;
> + ELSIF (NOT Type.IsEqual (ta, tb, NIL)) THEN
> Error.Txt (name, "incompatible argument types");
> ELSIF (ta = Int.T) OR (ta = LInt.T) OR (Type.IsOrdinal (ta)) THEN
> (* ok *)
> @@ -39,7 +42,11 @@
> Error.Txt (name, "wrong argument types");
> ta := Int.T;
> END;
> - ce.type := ta;
> + IF resultType # NIL THEN
> + ce.type := resultType;
> + ELSE
> + ce.type := ta;
> + END;
> END DoCheck;
>
> PROCEDURE Compile (ce: CallExpr.T) =
> Index: exprs/AddExpr.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/AddExpr.m3,v
> retrieving revision 1.3
> diff -u -r1.3 AddExpr.m3
> --- exprs/AddExpr.m3 4 May 2008 11:03:45 -0000 1.3
> +++ exprs/AddExpr.m3 8 Jan 2010 07:35:43 -0000
> @@ -67,6 +67,7 @@
>
> PROCEDURE Check (p: P; VAR cs: Expr.CheckState) =
> VAR ta, tb, range: Type.T;
> + resultType: Type.T := NIL;
> BEGIN
> Expr.TypeCheck (p.a, cs);
> Expr.TypeCheck (p.b, cs);
> @@ -74,8 +75,9 @@
> tb := Type.Base (Expr.TypeOf (p.b));
> IF (ta = Int.T) AND (tb = Int.T) THEN
> p.class := Class.cINT;
> - ELSIF (ta = LInt.T) AND (tb = LInt.T) THEN
> - p.class := Class.cLINT
> + ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
> + p.class := Class.cLINT;
> + resultType := LInt.T;
> ELSIF (ta = Reel.T) AND (tb = Reel.T) THEN
> p.class := Class.cREAL;
> ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
> @@ -96,7 +98,11 @@
> ELSE
> ta := Expr.BadOperands ("\'+\'", ta, tb);
> END;
> - p.type := ta;
> + IF resultType # NIL THEN
> + p.type := resultType;
> + ELSE
> + p.type := ta;
> + END;
> END Check;
>
> PROCEDURE Prep (p: P) =
> Index: exprs/DivExpr.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/DivExpr.m3,v
> retrieving revision 1.5
> diff -u -r1.5 DivExpr.m3
> --- exprs/DivExpr.m3 4 May 2008 11:03:46 -0000 1.5
> +++ exprs/DivExpr.m3 8 Jan 2010 07:35:43 -0000
> @@ -60,7 +60,7 @@
> tb := Type.Base (Expr.TypeOf (p.b));
> IF (ta = Int.T) AND (tb = Int.T) THEN
> p.type := Int.T;
> - ELSIF (ta = LInt.T) AND (tb = LInt.T) THEN
> + ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
> p.type := LInt.T;
> ELSE
> p.type := Expr.BadOperands ("DIV", ta, tb);
> Index: exprs/ModExpr.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/ModExpr.m3,v
> retrieving revision 1.5
> diff -u -r1.5 ModExpr.m3
> --- exprs/ModExpr.m3 4 May 2008 11:03:46 -0000 1.5
> +++ exprs/ModExpr.m3 8 Jan 2010 07:35:43 -0000
> @@ -60,6 +60,7 @@
>
> PROCEDURE Check (p: P; VAR cs: Expr.CheckState) =
> VAR ta, tb: Type.T;
> + resultType: Type.T := NIL;
> BEGIN
> Expr.TypeCheck (p.a, cs);
> Expr.TypeCheck (p.b, cs);
> @@ -67,8 +68,18 @@
> tb := Type.Base (Expr.TypeOf (p.b));
> IF (ta = Int.T) AND (tb = Int.T) THEN
> p.class := Class.cINT;
> +
> ELSIF (ta = LInt.T) AND (tb = LInt.T) THEN
> p.class := Class.cLINT;
> +
> + (* The result of MOD cannot be higher than either of its inputs.
> + * small divided by big is 0 remainder small
> + * big divided by small has a remainder of at most small
> + *)
> + ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
> + p.class := Class.cINT;
> + resultType := Int.T;
> +
> ELSIF (ta = Reel.T) AND (tb = Reel.T) THEN
> p.class := Class.cREAL;
> ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
> @@ -78,7 +89,11 @@
> ELSE p.class := Class.cERR; ta := Int.T;
> ta := Expr.BadOperands ("MOD", ta, tb);
> END;
> - p.type := ta;
> + IF resultType # NIL THEN
> + p.type := resultType;
> + ELSE
> + p.type := ta;
> + END;
> END Check;
>
> PROCEDURE Prep (p: P) =
> Index: exprs/MultiplyExpr.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/MultiplyExpr.m3,v
> retrieving revision 1.3
> diff -u -r1.3 MultiplyExpr.m3
> --- exprs/MultiplyExpr.m3 4 May 2008 11:03:46 -0000 1.3
> +++ exprs/MultiplyExpr.m3 8 Jan 2010 07:35:43 -0000
> @@ -66,6 +66,7 @@
>
> PROCEDURE Check (p: P; VAR cs: Expr.CheckState) =
> VAR ta, tb, range: Type.T;
> + resultType: Type.T := NIL;
> BEGIN
> Expr.TypeCheck (p.a, cs);
> Expr.TypeCheck (p.b, cs);
> @@ -73,8 +74,9 @@
> tb := Type.Base (Expr.TypeOf (p.b));
> IF (tb = Int.T) AND (ta = Int.T) THEN
> p.class := cINT;
> - ELSIF (tb = LInt.T) AND (ta = LInt.T) THEN
> + ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
> p.class := cLINT;
> + resultType := LInt.T;
> ELSIF (tb = Reel.T) AND (ta = Reel.T) THEN
> p.class := cREAL;
> ELSIF (tb = LReel.T) AND (ta = LReel.T) THEN
> @@ -90,7 +92,11 @@
> ta := Expr.BadOperands ("\'*\'", ta, tb);
> p.class := cINT;
> END;
> - p.type := ta;
> + IF resultType # NIL THEN
> + p.type := resultType;
> + ELSE
> + p.type := ta;
> + END;
> END Check;
>
> PROCEDURE Prep (p: P) =
> Index: exprs/SubtractExpr.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/exprs/SubtractExpr.m3,v
> retrieving revision 1.4
> diff -u -r1.4 SubtractExpr.m3
> --- exprs/SubtractExpr.m3 4 May 2008 11:03:46 -0000 1.4
> +++ exprs/SubtractExpr.m3 8 Jan 2010 07:35:43 -0000
> @@ -73,6 +73,7 @@
>
> PROCEDURE Check (p: P; VAR cs: Expr.CheckState) =
> VAR ta, tb, range: Type.T;
> + resultType: Type.T := NIL;
> BEGIN
> Expr.TypeCheck (p.a, cs);
> Expr.TypeCheck (p.b, cs);
> @@ -80,8 +81,9 @@
> tb := Type.Base (Expr.TypeOf (p.b));
> IF (ta = Int.T) AND (tb = Int.T) THEN
> p.class := Class.cINT;
> - ELSIF (ta = LInt.T) AND (tb = LInt.T) THEN
> + ELSIF (ta = LInt.T OR ta = Int.T) AND (tb = LInt.T OR tb = Int.T) THEN
> p.class := Class.cLINT;
> + resultType := LInt.T;
> ELSIF (ta = Reel.T) AND (tb = Reel.T) THEN
> p.class := Class.cREAL;
> ELSIF (ta = LReel.T) AND (tb = LReel.T) THEN
> @@ -113,7 +115,11 @@
> ta := Expr.BadOperands ("\'-\'", ta, tb);
> p.class := Class.cINT;
> END;
> - p.type := ta;
> + IF resultType # NIL THEN
> + p.type := resultType;
> + ELSE
> + p.type := ta;
> + END;
> END Check;
>
> PROCEDURE Prep (p: P) =
> Index: types/Type.m3
> ===================================================================
> RCS file: /usr/cvs/cm3/m3-sys/m3front/src/types/Type.m3,v
> retrieving revision 1.8
> diff -u -r1.8 Type.m3
> --- types/Type.m3 4 May 2008 11:03:49 -0000 1.8
> +++ types/Type.m3 8 Jan 2010 07:35:43 -0000
> @@ -543,6 +543,10 @@
> IF IsEqual (a, b, NIL) OR IsSubtype (b, a) THEN
> RETURN TRUE;
> ELSIF IsOrdinal (a) THEN
> + (* INTEGER is assignable to LONGINT *)
> + IF a = LInt.T AND b = Int.T THEN
> + RETURN TRUE;
> + END;
> (* ordinal types: OK if there is a common supertype
> and they have at least one member in common. *)
> IF IsEqual (Base(a), Base(b), NIL)
>
>
>
>
>
>
More information about the M3devel
mailing list