[M3devel] mixing INTEGER and LONGINT?

Rodney M. Bates rodney_bates at lcwb.coop
Fri Jan 8 18:33:52 CET 2010



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

Making INTEGER and LONGINT mutually assignable (or even one-way
assignability of INTEGER to LONGINT) implies all of the above.
The arithmetic operators are defined as generalizations of Modula-3
procedures, with parameters of VALUE mode.  And the rule for VALUE
requires only that the actual be assignable to the formal, not
have identical type.  This is what I originally proposed.

Actually, with LONGINT in the picture, the arithmetic operators have
to be defined more carefully, in order to avoid or remove ambiguity in
resolution of builtin overloaded arithmetic operators. Particularly,
we have to eliminate the possibility that, e.g., an expression of the form
INTEGER <op> INTEGER would resolve to the LONGINT <op> LONGINT -> LONGINT
operator, by assignability of INTEGER to LONGINT.  This would completely
the efficiency of native machine arithmetic.

Whatever we do, I feel very strongly that we should preserve consistency
with both the existing rules that assignment statements and passing
VALUE parameters require assignability.  That means that explicitly coded
VAL/ORD functions will be required either in both assignments and mixed
arithmetic, or neither.  The same applies to a number of other places
that require assignability.


>  
> 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