Copyright (C) 1992, Digital Equipment Corporation
All rights reserved.
See the file COPYRIGHT for a full description.
MODULE M3CharPreds;
IMPORT AST, ASTWalk;
IMPORT M3AST_AS;
IMPORT M3AST_AS_F, M3AST_SM_F, M3AST_TM_F;
IMPORT M3CStdProcs, M3CStdTypes, M3CTypesMisc, M3ASTNext;
IMPORT SeqM3AST_AS_EXP, SeqM3AST_AS_M3TYPE;
IMPORT SeqM3AST_AS_Fields, SeqM3AST_AS_Field_id;
IMPORT SeqM3AST_AS_Override, SeqM3AST_AS_Method;
IMPORT SeqM3AST_AS_FORMAL_ID, SeqM3AST_AS_Formal_param;
IMPORT M3Error, M3CSrcPos, M3CGo;
PROCEDURE Es (e: M3AST_AS.EXP): BOOLEAN RAISES {} =
BEGIN
TYPECASE e OF
| M3AST_AS.Call (call) =>
VAR st_call: M3CStdProcs.T;
BEGIN
IF M3CStdProcs.IsStandardCall(call, st_call) THEN
CASE st_call OF
| M3CStdProcs.T.First, M3CStdProcs.T.Last,
M3CStdProcs.T.Number =>
WITH ta = SeqM3AST_AS_EXP.First(call.sm_actual_s) DO
RETURN Tn(ta.sm_exp_type_spec); END;
| M3CStdProcs.T.BitSize, M3CStdProcs.T.ByteSize,
M3CStdProcs.T.AdrSize =>
WITH ta = SeqM3AST_AS_EXP.First(call.sm_actual_s) DO
RETURN TC(ta.sm_exp_type_spec, Ts); END;
ELSE END; END;
END;
ELSE END;
RETURN FALSE;
END Es;
TYPE
EcsClosure = ASTWalk.Closure OBJECT
ecs := FALSE;
OVERRIDES
callback := EcsHelper; END;
PROCEDURE Ecs (e: M3AST_AS.EXP): BOOLEAN =
<*FATAL ANY*>
BEGIN
WITH cl = NEW(EcsClosure) DO
EVAL cl.init();
ASTWalk.VisitNodes(e, cl);
RETURN cl.ecs;
END;
END Ecs;
PROCEDURE EcsHelper ( cl: EcsClosure;
n : AST.NODE;
<*UNUSED *> vm: ASTWalk.VisitMode)
RAISES {ASTWalk.Aborted} =
BEGIN
TYPECASE n OF
| M3AST_AS.Exp_used_id (e) =>
WITH def = e.vUSED_ID.sm_def DO
TYPECASE def OF
| M3AST_AS.Const_id (c) =>
IF Ecs(c.vINIT_ID.sm_init_exp) THEN
cl.ecs := TRUE;
ASTWalk.Abort() END;
ELSE END; (* typecase *)
END; (* with *)
| M3AST_AS.TYPE_SPEC => ASTWalk.IgnoreChildren(cl);
| M3AST_AS.EXP (e) =>
IF Es(e) THEN cl.ecs := TRUE; ASTWalk.Abort() END;
ELSE END; (* typecase *)
END EcsHelper;
PROCEDURE Tn (ts: M3AST_AS.TYPE_SPEC): BOOLEAN =
BEGIN
TYPECASE ts OF
| M3AST_AS.Enumeration_type (x) =>
RETURN x = M3CStdTypes.Char();
| M3AST_AS.Array_type (x) => RETURN ArrayTnOf(x);
| M3AST_AS.Subrange_type (x) =>
RETURN Ecs(x.as_range.as_exp1) OR Ecs(x.as_range.as_exp2);
ELSE END; (* typecase *)
RETURN FALSE;
END Tn;
PROCEDURE ArrayTnOf (ts: M3AST_AS.TYPE_SPEC): BOOLEAN =
BEGIN
TYPECASE ts OF
| M3AST_AS.Array_type (x) =>
VAR
iter := SeqM3AST_AS_M3TYPE.NewIter(x.as_indextype_s);
y: M3AST_AS.M3TYPE;
BEGIN
WHILE SeqM3AST_AS_M3TYPE.Next(iter, y) DO
IF Tn(M3TYPE_To_TYPE_SPEC(y)) THEN RETURN TRUE END; END; (* while *)
END;
ELSE END; (* typecase *)
RETURN FALSE;
END ArrayTnOf;
PROCEDURE Th (ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {} =
BEGIN
TYPECASE ts OF
| M3AST_AS.Array_type (x) => RETURN ArrayTnOf(x);
| M3AST_AS.Set_type (x) =>
RETURN Tn(M3TYPE_To_TYPE_SPEC(x.as_type));
ELSE END;
RETURN FALSE;
END Th;
PROCEDURE Tr (ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {} =
BEGIN
TYPECASE ts OF
| M3AST_AS.Array_type, M3AST_AS.Set_type => RETURN Th(ts);
| M3AST_AS.Packed_type (x) =>
RETURN
Ecs(x.as_exp) OR TC(M3TYPE_To_TYPE_SPEC(x.as_type), Ts);
ELSE END;
RETURN FALSE;
END Tr;
PROCEDURE Ts (ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {} =
BEGIN
RETURN Tn(ts) OR Tr(ts);
END Ts;
PROCEDURE TC (ts: M3AST_AS.TYPE_SPEC; tp: PredTypeProc): BOOLEAN
RAISES {} =
BEGIN
IF tp(ts) THEN
RETURN TRUE
ELSE
TYPECASE ts OF
| M3AST_AS.Array_type (x) =>
RETURN TC(M3TYPE_To_TYPE_SPEC(x.as_elementtype), tp);
| M3AST_AS.Packed_type (x) =>
RETURN TC(M3TYPE_To_TYPE_SPEC(x.as_type), tp);
| M3AST_AS.Record_type (x) =>
VAR
iter := M3ASTNext.NewIterField(x.as_fields_s);
field_id: M3AST_AS.Field_id;
BEGIN
WHILE M3ASTNext.Field(iter, field_id) DO
IF TC(field_id.sm_type_spec, tp) THEN
RETURN TRUE END; END;
END;
ELSE END; (* typecase *)
END; (* if *)
RETURN FALSE;
END TC;
PROCEDURE TCO (ts: M3AST_AS.TYPE_SPEC; tp: PredTypeProc): BOOLEAN
RAISES {} =
VAR rts := M3CTypesMisc.Reveal(ts);
BEGIN
TYPECASE rts OF
| NULL =>
M3Error.ReportAtPos(
M3CSrcPos.Null, "M3CTypesMisc.Reveal(...)=NIL");
| M3AST_AS.Object_type (x) =>
VAR
iter := M3ASTNext.NewIterObjectField(x);
field_id: M3AST_AS.Field_id;
BEGIN
WHILE M3ASTNext.ObjectField(iter, field_id) DO
IF field_id.sm_type_spec = NIL THEN
M3Error.ReportWithId(
field_id, "No sm_type_spec for field %s", field_id.lx_symrep);
ELSIF TC(field_id.sm_type_spec, tp) THEN
RETURN TRUE END; END;
END
ELSE END;
RETURN FALSE
END TCO;
TYPE
RefStack = REF RECORD
len : INTEGER := 0;
elts: REF ARRAY OF REFANY;
next: RefStack := NIL END;
PROCEDURE RefStack_Push (rs: RefStack; elt: REFANY) RAISES {} =
BEGIN
IF rs.len = NUMBER(rs.elts^) THEN
WITH na = NEW(REF ARRAY OF REFANY, rs.len * 2) DO
FOR i := 0 TO rs.len - 1 DO na[i] := rs.elts[i] END;
rs.elts := na; END END;
rs.elts[rs.len] := elt;
INC(rs.len);
END RefStack_Push;
PROCEDURE RefStack_Pop (rs: RefStack; elt: REFANY) RAISES {} =
BEGIN
IF rs.elts[rs.len - 1] # elt THEN
M3Error.ReportAtPos(M3CSrcPos.Null, "RefStack_Pop fails")
ELSE
DEC(rs.len) END
END RefStack_Pop;
PROCEDURE RefStack_Has (rs: RefStack; elt: REFANY): BOOLEAN
RAISES {} =
VAR elts := rs.elts;
BEGIN
FOR i := 0 TO rs.len - 1 DO
IF elts[i] = elt THEN RETURN TRUE END; END;
RETURN FALSE;
END RefStack_Has;
VAR
stackPool := NEW(MUTEX);
stacks : RefStack := NIL;
PROCEDURE Grade (ts: M3AST_AS.TYPE_SPEC): Char_Grade RAISES {} =
BEGIN
IF NOT Tm(ts) THEN
RETURN Char_Grade.No
ELSIF TC(ts, Ts) THEN
RETURN Char_Grade.TcTs
ELSE
RETURN Char_Grade.Td END
END Grade;
PROCEDURE Tm (ts: M3AST_AS.TYPE_SPEC): BOOLEAN RAISES {} =
VAR rs: RefStack;
BEGIN
LOCK stackPool DO
IF stacks = NIL THEN
rs := NEW(RefStack, elts := NEW(REF ARRAY OF REFANY, 100));
ELSE
rs := stacks;
stacks := stacks.next END; END;
TRY
RETURN TmW(ts, rs)
FINALLY
LOCK stackPool DO rs.next := stacks; stacks := rs; END END
END Tm;
PROCEDURE TmW (ts: M3AST_AS.M3TYPE; rs: RefStack): BOOLEAN
RAISES {} =
BEGIN
IF RefStack_Has(rs, ts) THEN RETURN FALSE END;
RefStack_Push(rs, ts);
TRY
TYPECASE ts OF
| M3AST_AS.Named_type (x) => RETURN TmW(x.sm_type_spec, rs);
| M3AST_AS.FLOAT_TYPE, M3AST_AS.INT_TYPE,
M3AST_AS.Null_type, M3AST_AS.RefAny_type,
M3AST_AS.Address_type, M3AST_AS.Root_type =>
RETURN FALSE;
| M3AST_AS.Packed_type (x) =>
RETURN Ecs(x.as_exp) OR TmW(x.as_type, rs);
| M3AST_AS.Array_type (x) =>
RETURN
TmW(x.as_elementtype, rs)
OR SeqTmW(x.as_indextype_s, rs);
| M3AST_AS.Enumeration_type (x) =>
RETURN x = M3CStdTypes.Char();
| M3AST_AS.Set_type (x) => RETURN TmW(x.as_type, rs);
| M3AST_AS.Subrange_type (x) =>
IF x.sm_base_type_spec # NIL
AND TmW(x.sm_base_type_spec, rs) THEN
RETURN TRUE END;
RETURN
Ecs(x.as_range.as_exp1) OR Ecs(x.as_range.as_exp2);
| M3AST_AS.Record_type (x) =>
RETURN FieldsTmW(x.as_fields_s, rs);
| M3AST_AS.Ref_type (x) => RETURN TmW(x.as_type, rs);
| M3AST_AS.Object_type (x) =>
IF x.as_ancestor # NIL AND TmW(x.as_ancestor, rs) THEN
RETURN TRUE END;
IF FieldsTmW(x.as_fields_s, rs) THEN RETURN TRUE END;
IF MethodsTmW(x.as_method_s, rs) THEN RETURN TRUE END;
IF OverridesTmW(x.as_override_s, rs) THEN
RETURN TRUE END;
RETURN FALSE;
| M3AST_AS.Procedure_type (x) =>
IF x.as_result_type # NIL AND TmW(x.as_result_type, rs) THEN
RETURN TRUE END;
IF FormalsTmW(x.as_formal_param_s, rs) THEN
RETURN TRUE END;
RETURN FALSE;
| M3AST_AS.Opaque_type (x) => RETURN TmW(x.as_type, rs);
| M3AST_AS.TYPE_SPEC(x) =>
ReportInUnit(x.tmp_unit_id, ts, "Unexpected case of TYPE_SPEC");
RETURN FALSE;
ELSE
M3Error.ReportAtPos(M3CSrcPos.Null, "Unexpected case of M3TYPE");
RETURN FALSE END;
FINALLY
RefStack_Pop(rs, ts); END;
END TmW;
PROCEDURE SeqTmW (seq: SeqM3AST_AS_M3TYPE.T; rs: RefStack): BOOLEAN
RAISES {} =
VAR i := SeqM3AST_AS_M3TYPE.NewIter(seq);
VAR t: M3AST_AS.M3TYPE;
BEGIN
WHILE SeqM3AST_AS_M3TYPE.Next(i, t) DO
IF TmW(t, rs) THEN RETURN TRUE END; END;
RETURN FALSE;
END SeqTmW;
PROCEDURE FieldsTmW (seq: SeqM3AST_AS_Fields.T; rs: RefStack):
BOOLEAN RAISES {} =
VAR i := SeqM3AST_AS_Fields.NewIter(seq);
VAR j: SeqM3AST_AS_Field_id.Iter;
VAR fs: M3AST_AS.Fields;
VAR fid: M3AST_AS.Field_id;
BEGIN
WHILE SeqM3AST_AS_Fields.Next(i, fs) DO
j := SeqM3AST_AS_Field_id.NewIter(fs.as_id_s);
WHILE SeqM3AST_AS_Field_id.Next(j, fid) DO
IF fid.sm_type_spec # NIL AND TmW(fid.sm_type_spec, rs) THEN
RETURN TRUE
ELSE
EXIT END END END;
RETURN FALSE;
END FieldsTmW;
PROCEDURE MethodsTmW (seq: SeqM3AST_AS_Method.T; rs: RefStack):
BOOLEAN RAISES {} =
VAR i := SeqM3AST_AS_Method.NewIter(seq);
VAR m: M3AST_AS.Method;
BEGIN
WHILE SeqM3AST_AS_Method.Next(i, m) DO
IF TmW(m.as_type, rs) THEN RETURN TRUE END; END;
RETURN FALSE;
END MethodsTmW;
PROCEDURE OverridesTmW (seq: SeqM3AST_AS_Override.T; rs: RefStack):
BOOLEAN RAISES {} =
VAR i := SeqM3AST_AS_Override.NewIter(seq);
VAR o: M3AST_AS.Override;
BEGIN
WHILE SeqM3AST_AS_Override.Next(i, o) DO
IF o.as_id.sm_type_spec # NIL
AND TmW(o.as_id.sm_type_spec, rs) THEN
RETURN TRUE END; END;
RETURN FALSE;
END OverridesTmW;
PROCEDURE FormalsTmW (seq: SeqM3AST_AS_Formal_param.T; rs: RefStack):
BOOLEAN RAISES {} =
VAR i := SeqM3AST_AS_Formal_param.NewIter(seq);
VAR j: SeqM3AST_AS_FORMAL_ID.Iter;
VAR fp: M3AST_AS.Formal_param;
VAR fid: M3AST_AS.FORMAL_ID;
BEGIN
WHILE SeqM3AST_AS_Formal_param.Next(i, fp) DO
j := SeqM3AST_AS_FORMAL_ID.NewIter(fp.as_id_s);
WHILE SeqM3AST_AS_FORMAL_ID.Next(j, fid) DO
IF fid.sm_type_spec # NIL AND TmW(fid.sm_type_spec, rs) THEN
RETURN TRUE
ELSE
EXIT END END (*do*) END (*do*);
RETURN FALSE;
END FormalsTmW;
PROCEDURE M3TYPE_To_TYPE_SPEC (m: M3AST_AS.M3TYPE):
M3AST_AS.TYPE_SPEC =
VAR ts: M3AST_AS.TYPE_SPEC;
BEGIN
IF m=NIL THEN RETURN NIL END;
M3CTypesMisc.GetTYPE_SPECFromM3TYPE(m, ts);
RETURN ts;
END M3TYPE_To_TYPE_SPEC;
PROCEDURE ReportInUnit(unit : M3AST_AS.UNIT_ID;
n : M3Error.ERROR_NODE;
message: TEXT) RAISES {} =
BEGIN
M3Error.SetCu(unit.sm_spec.sm_comp_unit);
M3Error.Report(n, message);
M3Error.SetCu(M3CGo.Current());
END ReportInUnit;
BEGIN
END M3CharPreds.