MODULE M3CTypesMisc;
*************************************************************************
Copyright (C) Olivetti 1989
All Rights reserved
Use and copy of this software and preparation of derivative works based
upon this software are permitted to any person, provided this same
copyright notice and the following Olivetti warranty disclaimer are
included in any copy of the software or any modification thereof or
derivative work therefrom made by any person.
This software is made available AS IS and Olivetti disclaims all
warranties with respect to this software, whether expressed or implied
under any law, including all implied warranties of merchantibility and
fitness for any purpose. In no event shall Olivetti be liable for any
damages whatsoever resulting from loss of use, data or profits or
otherwise arising out of or in connection with the use or performance
of this software.
*************************************************************************
IMPORT M3AST_LX, M3AST_AS, M3AST_SM, M3ASTNext;
IMPORT M3AST_AS_F, M3AST_SM_F;
IMPORT SeqM3AST_AS_M3TYPE, SeqM3AST_AS_Fields, SeqM3AST_AS_Enum_id,
SeqM3AST_AS_Override;
IMPORT M3CBackEnd, M3COrdinal, M3CConcTypeSpec;
PROCEDURE GetTYPE_SPECFromM3TYPE(
t: M3AST_AS.M3TYPE;
VAR (*out*) ts: M3AST_SM.TYPE_SPEC_UNSET)
RAISES {}=
BEGIN
TYPECASE t OF <*NOWARN*>
| M3AST_AS.Named_type(namedType) =>
ts := namedType.sm_type_spec;
| M3AST_AS.TYPE_SPEC(typeSpec) =>
ts := typeSpec;
| M3AST_AS.Bad_M3TYPE =>
ts := NIL;
END;
END GetTYPE_SPECFromM3TYPE;
PROCEDURE Unpack(
p: M3AST_AS.Packed_type)
: M3AST_SM.TYPE_SPEC_UNSET
RAISES {}=
VAR
unpacked: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
LOOP
GetTYPE_SPECFromM3TYPE(p.as_type, unpacked);
TYPECASE unpacked OF
| NULL =>
RETURN NIL;
| M3AST_AS.Packed_type(packed) =>
p := packed; (* and loop *)
ELSE
RETURN unpacked;
END;
END;
END Unpack;
PROCEDURE CheckedUnpack(
t: M3AST_SM.TYPE_SPEC_UNSET)
: M3AST_SM.TYPE_SPEC_UNSET
RAISES {}=
BEGIN
TYPECASE t OF
| NULL => RETURN NIL;
| M3AST_AS.Packed_type(p) => RETURN Unpack(p);
ELSE
RETURN t;
END;
END CheckedUnpack;
PROCEDURE Reveal(
ts: M3AST_SM.TYPE_SPEC_UNSET)
: M3AST_SM.TYPE_SPEC_UNSET
RAISES {}=
BEGIN
LOOP
IF ts = NIL THEN RETURN ts
ELSIF ISTYPE(ts, M3AST_AS.Opaque_type) THEN
ts := M3CConcTypeSpec.CurrentReveal(ts);
ELSE
RETURN ts;
END;
END;
END Reveal;
PROCEDURE Concrete(
ts: M3AST_SM.TYPE_SPEC_UNSET)
: M3AST_SM.TYPE_SPEC_UNSET
RAISES {}=
VAR
reveal := M3CConcTypeSpec.CurrentReveal(ts);
BEGIN
IF (reveal # ts) AND
(NARROW(ts, M3AST_AS.Opaque_type).sm_concrete_type_spec = reveal) THEN
RETURN reveal;
ELSE
RETURN ts;
END;
END Concrete;
PROCEDURE IsConcrete(
ts: M3AST_SM.TYPE_SPEC_UNSET;
fully: BOOLEAN)
: BOOLEAN
RAISES {}=
VAR
typeSpec: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
TYPECASE ts OF
| NULL =>
RETURN TRUE;
| M3AST_AS.Object_type(object) =>
IF fully AND M3ASTNext.SimpleSuperType(object, typeSpec) THEN
RETURN IsConcrete(typeSpec, TRUE);
ELSE
RETURN TRUE;
END;
| M3AST_AS.Opaque_type(opaque) =>
typeSpec := M3CConcTypeSpec.CurrentReveal(ts);
IF (typeSpec # ts) AND
(opaque.sm_concrete_type_spec = typeSpec) THEN
RETURN (NOT fully) OR IsConcrete(typeSpec, TRUE);
ELSE
RETURN FALSE;
END;
ELSE
RETURN TRUE;
END;
END IsConcrete;
PROCEDURE Index(
a: M3AST_AS.Array_type;
VAR index: M3AST_SM.TYPE_SPEC_UNSET)
: Ix
RAISES {}=
VAR
i := SeqM3AST_AS_M3TYPE.NewIter(a.as_indextype_s);
m3Type: M3AST_AS.M3TYPE;
BEGIN
IF SeqM3AST_AS_M3TYPE.Next(i, m3Type) THEN
GetTYPE_SPECFromM3TYPE(m3Type, index);
LOOP
TYPECASE index OF
| NULL =>
RETURN Ix.Unknown;
| M3AST_AS.Integer_type,
M3AST_AS.Enumeration_type,
M3AST_AS.Subrange_type =>
RETURN Ix.Ordinal;
| M3AST_AS.Packed_type(packed) =>
index := Unpack(packed);
(* loop and try again *)
ELSE
RETURN Ix.Bad;
END; (* case *)
END;
ELSE
RETURN Ix.Open;
END; (* if *)
END Index;
PROCEDURE Indexable(
ts: M3AST_SM.TYPE_SPEC_UNSET;
VAR a: M3AST_AS.Array_type)
: BOOLEAN
RAISES {}=
BEGIN
TYPECASE Concrete(CheckedUnpack(ts)) OF
| M3AST_AS.Array_type(arrayType) =>
a := arrayType;
RETURN TRUE; (* NIL case ok *)
| M3AST_AS.Ref_type(refType) =>
VAR
referent: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
GetTYPE_SPECFromM3TYPE(refType.as_type, referent);
TYPECASE CheckedUnpack(referent) OF
| M3AST_AS.Array_type(arrayType) =>
a := arrayType; (* NIL case ok *)
RETURN TRUE;
ELSE
END;
END;
ELSE
END;
RETURN FALSE;
END Indexable;
PROCEDURE IsRef(ts: M3AST_SM.TYPE_SPEC_UNSET): BOOLEAN RAISES {}=
BEGIN
IF ts = NIL THEN RETURN TRUE END;
TYPECASE ts OF
| M3AST_AS.RefAny_type, M3AST_AS.Root_type,
M3AST_AS.Address_type,
M3AST_AS.Ref_type, M3AST_AS.Object_type,
M3AST_AS.Opaque_type, M3AST_AS.Null_type =>
RETURN TRUE;
ELSE
RETURN FALSE;
END; (* case *)
END IsRef;
CONST
BadSuperType = RefSet{Ref.Null, Ref.Not};
PROCEDURE IsTracedObject(o: M3AST_AS.Object_type): Ref RAISES {}=
VAR
super: M3AST_SM.TYPE_SPEC_UNSET;
traced: Ref;
BEGIN
IF M3ASTNext.SimpleSuperType(o, super) THEN
traced := IsTracedRef(super);
IF traced IN BadSuperType THEN RETURN Ref.Unknown ELSE RETURN traced END;
ELSE
RETURN Ref.Traced;
END;
END IsTracedObject;
PROCEDURE IsTracedRef(type: M3AST_SM.TYPE_SPEC_UNSET): Ref RAISES {}=
BEGIN
IF type = NIL THEN RETURN Ref.Unknown END;
TYPECASE type OF
| M3AST_AS.RefAny_type =>
RETURN Ref.Traced;
| M3AST_AS.Address_type =>
RETURN Ref.Untraced;
| M3AST_AS.Root_type(root_type) =>
IF root_type.as_trace_mode = NIL THEN
RETURN Ref.Traced;
ELSE
RETURN Ref.Untraced;
END; (* if *)
| M3AST_AS.Ref_type(ref_type) =>
IF ref_type.as_trace_mode = NIL THEN
RETURN Ref.Traced;
ELSE
RETURN Ref.Untraced;
END; (* if *)
| M3AST_AS.Object_type(object_type) =>
RETURN IsTracedObject(object_type);
| M3AST_AS.Opaque_type =>
WITH ref = IsTracedRef(Reveal(type)) DO
IF ref IN BadSuperType THEN RETURN Ref.Unknown ELSE RETURN ref END;
END;
| M3AST_AS.Null_type =>
RETURN Ref.Null;
ELSE
RETURN Ref.Not;
END; (* case *)
END IsTracedRef;
PROCEDURE ContainsTracedFields(fields: SeqM3AST_AS_Fields.T): BOOLEAN RAISES {}=
VAR
iter := M3ASTNext.NewIterField(fields);
fieldId: M3AST_AS.Field_id;
BEGIN
WHILE M3ASTNext.Field(iter, fieldId) DO
IF IsTraced(fieldId.sm_type_spec) THEN RETURN TRUE END;
END; (* while *)
RETURN FALSE;
END ContainsTracedFields;
PROCEDURE IsTraced(type: M3AST_SM.TYPE_SPEC_UNSET): BOOLEAN RAISES {}=
BEGIN
TYPECASE type OF
| NULL =>
RETURN FALSE;
| M3AST_AS.RefAny_type =>
RETURN TRUE;
| M3AST_AS.Root_type(root) =>
RETURN root.as_trace_mode = NIL;
| M3AST_AS.Ref_type(ref) =>
RETURN ref.as_trace_mode = NIL;
| M3AST_AS.Object_type(object) =>
RETURN IsTracedObject(object) IN ProbablyTraced;
| M3AST_AS.Record_type(record) =>
RETURN ContainsTracedFields(record.as_fields_s);
| M3AST_AS.Array_type(array) =>
VAR
elementType: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
GetTYPE_SPECFromM3TYPE(array.as_elementtype, elementType);
RETURN IsTraced(elementType);
END;
| M3AST_AS.Packed_type(packed) =>
VAR
component: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
GetTYPE_SPECFromM3TYPE(packed.as_type, component);
RETURN IsTraced(component);
END;
ELSE
RETURN FALSE;
END; (* case *)
END IsTraced;
PROCEDURE IsOpenArray(type: M3AST_SM.TYPE_SPEC_UNSET): BOOLEAN RAISES {}=
BEGIN
TYPECASE type OF
| NULL => RETURN FALSE;
| M3AST_AS.Array_type(array) => RETURN SeqM3AST_AS_M3TYPE.Empty(array.as_indextype_s);
ELSE
RETURN FALSE;
END;
END IsOpenArray;
PROCEDURE IsEmpty(type: M3AST_SM.TYPE_SPEC_UNSET): BOOLEAN RAISES {}=
BEGIN
TYPECASE type OF
| NULL =>
RETURN FALSE;
| M3AST_AS.Enumeration_type(enum) =>
RETURN SeqM3AST_AS_Enum_id.Empty(enum.as_id_s);
| M3AST_AS.Subrange_type =>
VAR
first, last: M3AST_SM.Exp_value;
BEGIN
RETURN M3COrdinal.ValidBounds(type, first, last) AND
M3CBackEnd.Compare(first, last) > 0;
END;
| M3AST_AS.Array_type(array) =>
(* empty if element type is empty and primary index type is not empty;
If both element type and primary index type are empty the null
constructor is a valid value of the type *)
VAR
index, element: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
array := array.sm_norm_type;
GetTYPE_SPECFromM3TYPE(array.as_elementtype, element);
RETURN IsEmpty(element) AND Index(array, index) = Ix.Ordinal AND
NOT IsEmpty(index);
END;
| M3AST_AS.Packed_type(packed) =>
RETURN IsEmpty(Unpack(packed));
ELSE
RETURN FALSE;
END;
END IsEmpty;
PROCEDURE NoDefaultForMethod(
o: M3AST_AS.Object_type;
methodId: M3AST_AS.Method_id)
: BOOLEAN
RAISES {}=
VAR
id: M3AST_LX.Symbol_rep;
iter: SeqM3AST_AS_Override.Iter;
override: M3AST_AS.Override;
ts, concrete: M3AST_SM.TYPE_SPEC_UNSET;
BEGIN
IF methodId.vINIT_ID.sm_init_exp # NIL THEN RETURN FALSE END;
(* Assert: 'methodId' must be the defining occurence of the method. Only
the defining occurence has the option of having no default. *)
id := methodId.lx_symrep;
IF id = NIL THEN RETURN FALSE END;
LOOP
(* Search overrides at current level of object type *)
iter := SeqM3AST_AS_Override.NewIter(o.as_override_s);
WHILE SeqM3AST_AS_Override.Next(iter, override) DO
WITH mId = override.as_id DO
IF mId.lx_symrep = id AND mId.vREDEF_ID.sm_int_def = methodId THEN
RETURN FALSE; (* default found *)
END;
END;
END;
(* If no luck at the current level we look at the supertype *)
IF NOT M3ASTNext.SimpleSuperType(o, ts) THEN RETURN TRUE END;
LOOP
TYPECASE ts OF
| NULL =>
RETURN FALSE;
| M3AST_AS.Object_type(objectType) =>
o := objectType;
EXIT; (* to outer loop; search for default in supertype *)
| M3AST_AS.Opaque_type =>
concrete := Concrete(ts);
IF concrete = ts THEN
(* We don't know the concrete representation; so the default may
be hidden in the opaque supertype - we return FALSE *)
RETURN FALSE;
ELSE
ts := concrete;
(* Loop and check out the concrete supertype *)
END;
ELSE
RETURN FALSE; (* A cockup elsewhere; we pretend there's no problem *)
END;
END;
END;
END NoDefaultForMethod;
PROCEDURE HiddenObjectParameter(
p: M3AST_AS.Procedure_type;
VAR ts: M3AST_SM.TYPE_SPEC_UNSET)
: BOOLEAN
RAISES {}=
BEGIN
TYPECASE p.sm_def_id OF
| NULL => RETURN FALSE;
| M3AST_AS.METHOD_OVERRIDE_ID(methodId) =>
ts := methodId.vRECOBJ_ID.sm_enc_type_spec;
RETURN TRUE;
| M3AST_AS.Type_id(typeId) =>
ts := typeId.sm_type_spec;
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END HiddenObjectParameter;
BEGIN
END M3CTypesMisc.