blob: 64a8adf432d2ea274596bf64ceff63201923814c [file] [log] [blame]
(* M2Const.mod maintain and resolve the types of constants.
Copyright (C) 2010-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. *)
IMPLEMENTATION MODULE M2Const ;
(*
CONST
Debugging = FALSE ;
DebugConsts = FALSE ;
TYPE
constList = POINTER TO cList ;
cList = RECORD
constsym : CARDINAL ;
constmeta: constType ;
expr : CARDINAL ;
type : CARDINAL ;
next : constList ;
END ;
VAR
headOfConsts: constList ;
PROCEDURE stop ; BEGIN END stop ;
(*
addToConstList - add a constant, sym, to the head of the constants list.
*)
PROCEDURE addToConstList (sym: CARDINAL) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
IF h^.constsym=sym
THEN
InternalError ('should never see the same symbol id declared twice')
END ;
h := h^.next
END ;
NEW(h) ;
WITH h^ DO
constsym := sym ;
constmeta := unknown ;
expr := NulSym ;
type := NulSym ;
next := headOfConsts
END ;
headOfConsts := h
END addToConstList ;
(*
FixupConstAsString - fixes up a constant, sym, which will have the string type.
*)
PROCEDURE FixupConstAsString (sym: CARDINAL) ;
BEGIN
fixupConstMeta(sym, str)
END FixupConstAsString ;
(*
FixupConstType - fixes up a constant, sym, which will have the type, consttype.
*)
PROCEDURE FixupConstType (sym: CARDINAL; consttype: CARDINAL) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
IF constmeta=str
THEN
InternalError ('cannot fix up a constant to have a type if it is already known as a string')
END ;
type := consttype ;
PutConst(sym, consttype) ;
RETURN
END
END ;
h := h^.next
END
END FixupConstType ;
(*
FixupProcedureType - creates a proctype from a procedure.
*)
PROCEDURE FixupProcedureType (p: CARDINAL) : CARDINAL ;
VAR
par,
t : CARDINAL ;
n, i: CARDINAL ;
BEGIN
IF IsProcedure(p)
THEN
t := MakeProcType(CheckAnonymous(NulName)) ;
i := 1 ;
n := NoOfParam(p) ;
WHILE i<=n DO
par := GetParam(p, i) ;
IF IsParameterVar(par)
THEN
PutProcTypeVarParam(t, GetType(par), IsParameterUnbounded(par))
ELSE
PutProcTypeParam(t, GetType(par), IsParameterUnbounded(par))
END ;
INC(i)
END ;
IF GetType(p)#NulSym
THEN
PutFunction(t, GetType(p))
END ;
RETURN( t )
ELSE
InternalError ('expecting a procedure')
END ;
RETURN( NulSym )
END FixupProcedureType ;
(*
FixupConstProcedure - fixes up a constant, sym, which will be equivalent to e.
*)
PROCEDURE FixupConstProcedure (sym: CARDINAL; e: CARDINAL) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
expr := e ;
type := FixupProcedureType(e) ;
PutConst(sym, type) ;
RETURN
END
END ;
h := h^.next
END
END FixupConstProcedure ;
(*
FixupConstExpr - fixes up a constant, sym, which will be equivalent to e.
*)
PROCEDURE FixupConstExpr (sym: CARDINAL; e: CARDINAL) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
expr := e ;
RETURN
END
END ;
h := h^.next
END
END FixupConstExpr ;
(*
fixupConstMeta - fixes up symbol, sym, to have the, meta, constType.
*)
PROCEDURE FixupConstMeta (sym: CARDINAL; meta: constType) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
constmeta := meta ;
RETURN
END
END ;
h := h^.next
END
END FixupConstMeta ;
(*
fixupConstCast -
*)
PROCEDURE fixupConstCast (sym: CARDINAL; castType: CARDINAL) ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
type := castType ;
RETURN
END
END ;
h := h^.next
END
END fixupConstCast ;
(*
findConstType -
*)
PROCEDURE findConstType (sym: CARDINAL) : CARDINAL ;
VAR
h: constList ;
t: CARDINAL ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
t := GetType(sym) ;
IF t=NulSym
THEN
RETURN( NulSym )
ELSE
RETURN( t )
END
END
END ;
h := h^.next
END ;
RETURN( NulSym )
END findConstType ;
(*
findConstMeta -
*)
PROCEDURE findConstMeta (sym: CARDINAL) : constType ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF constsym=sym
THEN
RETURN( constmeta )
END
END ;
h := h^.next
END ;
RETURN( unknown )
END findConstMeta ;
(*
ReportUnresolvedConstTypes - emits an error message for any unresolved constant type.
*)
PROCEDURE ReportUnresolvedConstTypes ;
VAR
h: constList ;
BEGIN
h := headOfConsts ;
WHILE h#NIL DO
WITH h^ DO
IF (constmeta#unknown) AND (constmeta#str) AND (type=NulSym)
THEN
MetaError1('unable to resolve the type of the constant {%1Dad}', h^.constsym)
END
END ;
h := h^.next
END
END ReportUnresolvedConstTypes ;
(*
DebugMeta -
*)
PROCEDURE DebugMeta (h: constList) ;
VAR
n: Name ;
BEGIN
IF DebugConsts
THEN
WITH h^ DO
n := GetSymName(constsym) ;
printf1('constant %a ', n) ;
IF type=NulSym
THEN
printf0('type is unknown\n')
ELSE
printf0('type is known\n')
END
END
END
END DebugMeta ;
(*
constTypeResolved -
*)
PROCEDURE constTypeResolved (h: constList) : BOOLEAN ;
BEGIN
RETURN( h^.type#NulSym )
END constTypeResolved ;
(*
constExprResolved -
*)
PROCEDURE constExprResolved (h: constList) : BOOLEAN ;
BEGIN
RETURN( h^.expr#NulSym )
END constExprResolved ;
(*
findConstMetaExpr -
*)
PROCEDURE findConstMetaExpr (h: constList) : constType ;
BEGIN
RETURN( h^.constmeta )
END findConstMetaExpr ;
(*
constResolveViaMeta -
*)
PROCEDURE constResolveViaMeta (h: constList) : BOOLEAN ;
VAR
n: Name ;
BEGIN
WITH h^ DO
IF findConstMetaExpr(h)=str
THEN
PutConstStringKnown (constsym, MakeKey(''), FALSE, FALSE) ;
IF DebugConsts
THEN
n := GetSymName(constsym) ;
printf1('resolved constant %a as a string\n', n)
END ;
RETURN( TRUE )
END
END ;
RETURN( FALSE )
END constResolveViaMeta ;
(*
constResolvedViaType -
*)
PROCEDURE constResolvedViaType (h: constList) : BOOLEAN ;
VAR
n: Name ;
BEGIN
WITH h^ DO
type := findConstType(expr) ;
IF type#NulSym
THEN
PutConst(constsym, type) ;
IF DebugConsts
THEN
n := GetSymName(constsym) ;
printf1('resolved type of constant %a\n', n)
END ;
RETURN( TRUE )
END
END ;
RETURN( FALSE )
END constResolvedViaType ;
(*
resolveConstType -
*)
PROCEDURE resolveConstType (h: constList) : BOOLEAN ;
BEGIN
WITH h^ DO
IF (constmeta=unknown) OR (constmeta=str)
THEN
(* do nothing *)
ELSE
DebugMeta(h) ;
IF constTypeResolved(h)
THEN
(* nothing to do *)
ELSE
IF constExprResolved(h)
THEN
IF constResolveViaMeta(h)
THEN
RETURN( TRUE )
ELSIF constResolvedViaType(h)
THEN
RETURN( TRUE )
END
END
END
END
END ;
RETURN( FALSE )
END resolveConstType ;
(*
ResolveConstTypes - resolves the types of all aggegrate constants.
*)
PROCEDURE ResolveConstTypes ;
VAR
h : constList ;
changed: BOOLEAN ;
BEGIN
REPEAT
changed := FALSE ;
h := headOfConsts ;
WHILE h#NIL DO
changed := resolveConstType(h) ;
h := h^.next
END
UNTIL NOT changed ;
ReportUnresolvedConstTypes
END ResolveConstTypes ;
(*
SkipConst - returns the symbol which is a pseudonum of, sym.
*)
PROCEDURE SkipConst (sym: CARDINAL) : CARDINAL ;
VAR
init: CARDINAL ;
h : constList ;
BEGIN
init := sym ;
h := headOfConsts ;
WHILE h#NIL DO
IF (h^.constsym=sym) AND (h^.expr#NulSym)
THEN
sym := h^.expr ;
IF sym=init
THEN
(* circular definition found *)
RETURN( sym )
END ;
h := headOfConsts
ELSE
h := h^.next
END
END ;
RETURN( sym )
END SkipConst ;
BEGIN
headOfConsts := NIL
*)
BEGIN
END M2Const.