* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*)
+ *)
(* Domtool configuration language type checking *)
structure Tycheck :> TYCHECK = struct
-open Ast Print
+open Ast Print Env
-structure SS = StringSet
structure SM = StringMap
-type env = SS.set * typ SM.map
-val empty : env = (SS.add (SS.singleton "int", "string"),
- SM.empty)
-
-fun lookupType (ts, _) name = SS.member (ts, name)
-fun lookupVal (_, vs) name = SM.find (vs, name)
-
-fun bindType (ts, vs) name = (SS.add (ts, name), vs)
-fun bindVal (ts, vs) (name, t) = (ts, SM.insert (vs, name, t))
-
local
val unifCount = ref 0
in
| UnboundVariable of string
| WrongPred of string * pred * pred
-fun preface (s, d) = printd (PD.hovBox (PD.PPS.Rel 0,
- [PD.string s, PD.space 1, d]))
-
fun describe_unification_error t ue =
case ue of
UnifyPred (p1, p2) =>
TUnif (_, ref (SOME tAll)) => whnorm tAll
| _ => tAll
+fun baseCondition t =
+ case whnorm t of
+ (TBase name, _) => typeRule name
+ | (TList t, _) =>
+ (case baseCondition t of
+ NONE => NONE
+ | SOME f => SOME (fn (EList ls, _) => List.all f ls
+ | _ => false))
+ | _ => NONE
+
+fun hasTyp (e, t1, t2) =
+ if (case baseCondition t2 of
+ NONE => false
+ | SOME rule => rule e) then
+ ()
+ else
+ subTyp (t1, t2)
+
fun checkTyp G (tAll as (t, loc)) =
let
val err = ErrorMsg.error (SOME loc)
let
val t' = checkExp G e'
in
- (subTyp (t', t);
+ (hasTyp (eAll, t', t);
if isError t' then
(TList (TError, loc), loc)
else
NONE => (newUnif (), loc)
| SOME t => checkTyp G t
- val G' = bindVal G (x, t)
+ val G' = bindVal G (x, t, NONE)
val t' = checkExp G' e
in
(TArrow (t, t'), loc)
val tf = checkExp G func
val ta = checkExp G arg
in
- (subTyp (tf, (TArrow (dom, ran), loc));
- subTyp (ta, dom)
+ (hasTyp (func, tf, (TArrow (dom, ran), loc));
+ hasTyp (arg, ta, dom)
handle Unify ue =>
dte (WrongType ("Function argument",
arg,
| EGet (x, evar, rest) =>
let
val xt = (newUnif (), loc)
- val G' = bindVal G (x, xt)
+ val G' = bindVal G (x, xt, NONE)
val rt = whnorm (checkExp G' rest)
in
fun checkDecl G (d, _, loc) =
case d of
DExternType name => bindType G name
- | DExternVal (name, t) => bindVal G (name, checkTyp G t)
+ | DExternVal (name, t) => bindVal G (name, checkTyp G t, NONE)
+ | DVal (name, to, e) =>
+ let
+ val to =
+ case to of
+ NONE => (newUnif (), loc)
+ | SOME to => checkTyp G to
+
+ val t = checkExp G e
+ in
+ hasTyp (e, t, to)
+ handle Unify ue =>
+ describe_type_error loc
+ (WrongType ("Bound value",
+ e,
+ t,
+ to,
+ SOME ue));
+ bindVal G (name, to, SOME e)
+ end
fun checkFile G tInit (ds, eo) =
let
let
val t = checkExp G' e
in
- subTyp (t, tInit)
+ hasTyp (e, t, tInit)
handle Unify ue =>
(ErrorMsg.error (SOME loc) "Bad type for final expression of source file.";
preface ("Actual:", p_typ t);