juno-compiler/src/JunoChkBNF.m3


 Copyright (C) 1992, Digital Equipment Corporation                         
 All rights reserved.                                                      
 See the file COPYRIGHT for a full description.                            
                                                                           
 Last modified on Tue Jan 28 13:17:28 PST 1997 by heydon                   
      modified on Fri Aug  7 21:54:06 PDT 1992 by myers                    

MODULE JunoChkBNF;

IMPORT JunoAST, JunoCompileErr, JunoASTUtils;

PROCEDURE TotalCmd(cmd: JunoAST.Cmd) RAISES {JunoCompileErr.Error} =
  BEGIN
    TYPECASE cmd OF
      JunoAST.Skip, JunoAST.Abort, JunoAST.Halt => (* SKIP *)
    | JunoAST.Else (c) => PartialCmd(c.c1); TotalCmd(c.c2)
    | JunoAST.Proj (c) => DefinedHints(c.vars); TotalCmd(c.body)
    | JunoAST.Seq (c) => TotalCmd(c.c1); TotalCmd(c.c2)
    | JunoAST.GroupedCmd (c) => TotalCmd(c.body);
    | JunoAST.Assign (c) => QIdList(c.vars); ExprList(c.exprs)
    | JunoAST.ProcCall (c) => QIdList(c.inouts); ExprList(c.ins);
    | JunoAST.Do (c) => PartialCmd(c.body);
    | JunoAST.If (c) => PartialCmd(c.body);
    | JunoAST.Save (c) => TotalCmd(c.body);
    ELSE ExpectedError("Total Command", cmd)
    END
  END TotalCmd;

PROCEDURE DefinedHints(vars: JunoAST.NearVarList)
  RAISES {JunoCompileErr.Error} =
Raises Error if any of the variables in vars is hinted with an expression that could be undefined.
  VAR l := vars.head; BEGIN
    WHILE l # NIL DO
      IF l.hint # JunoAST.NilExpr AND
         NOT JunoASTUtils.AlwaysDefined(l.hint) THEN
        ExpectedError("Total Command", vars)
      END;
      l := l.next
    END
  END DefinedHints;

PROCEDURE PartialCmd(cmd: JunoAST.Cmd) RAISES {JunoCompileErr.Error} =
  BEGIN
    TYPECASE cmd OF
      JunoAST.Else (c) => PartialCmd(c.c1); PartialCmd(c.c2)
    | JunoAST.Proj (c) => PartialCmd(c.body);
    | JunoAST.Guard (c) => Formula(c.grd); PartialCmd(c.body);
    | JunoAST.Seq (c) => PartialCmd(c.c1); TotalCmd(c.c2)
    | JunoAST.Query (c) => Formula(c.f)
    | JunoAST.GroupedCmd (c) => PartialCmd(c.body);
    ELSE
      TRY TotalCmd(cmd) EXCEPT JunoCompileErr.Error (e) =>
        IF e.ast = cmd
          THEN ExpectedError("Partial Command", cmd)
          ELSE RAISE JunoCompileErr.Error(e)
        END
      END
    END
  END PartialCmd;

PROCEDURE Formula(form: JunoAST.Formula) RAISES {JunoCompileErr.Error} =
  BEGIN
    TYPECASE form OF
      JunoAST.Or (f) => Formula(f.f1); Formula(f.f2);
    | JunoAST.And (f) => Formula(f.f1); Formula(f.f2);
    | JunoAST.Not (f) => Formula(f.f);
    | JunoAST.True, JunoAST.False => (* SKIP *)
    | JunoAST.Exists (f) => Formula(f.f)
    | JunoAST.BIUPred (f) => Expr(f.e)
    | JunoAST.Relation (f) => Expr(f.e1); Expr(f.e2)
    | JunoAST.Call => PredicateCall(form)
    | JunoAST.GroupedExpr (f) => Formula(f.expr)
    ELSE ExpectedError("Formula", form)
    END
  END Formula;

PROCEDURE PredicateCall(call: JunoAST.Call) RAISES {JunoCompileErr.Error} =
  BEGIN
    IF call.inouts.size # 0 THEN
      ExpectedError("Predicate Call", call);
    END;
    ExprList(call.ins)
  END PredicateCall;

PROCEDURE Expr(expr: JunoAST.Expr) RAISES {JunoCompileErr.Error} =
  BEGIN
    TYPECASE expr OF
      JunoAST.Rel (e) => Expr(e.e1); Expr(e.e2)
    | JunoAST.BuiltInAddFunc (e) => Expr(e.e1); Expr(e.e2)
    | JunoAST.BuiltInMulFunc (e) => Expr(e.e1); Expr(e.e2)
    | JunoAST.UMinus (e) => Expr(e.e);
    | JunoAST.AtomicExpr => (* SKIP *)
    | JunoAST.BIUFunc (e) => Expr(e.e)
    | JunoAST.BIBFunc (e) => Expr(e.e1); Expr(e.e2)
    | JunoAST.List (e) => ExprList(e.elts)
    | JunoAST.Call (e) => QIdList(e.inouts); ExprList(e.ins)
    | JunoAST.GroupedExpr (e) => Expr(e.expr)
    ELSE ExpectedError("Expression", expr)
    END
  END Expr;

PROCEDURE QIdList(qids: JunoAST.ExprList) RAISES {JunoCompileErr.Error} =
  VAR curr := qids.head; BEGIN
    WHILE curr # NIL DO
      IF NOT ISTYPE(curr.expr, JunoAST.QId) THEN
        ExpectedError("QID", curr.expr)
      END;
      curr := curr.next;
    END
  END QIdList;

PROCEDURE ExprList(exprs: JunoAST.ExprList) RAISES {JunoCompileErr.Error} =
  VAR curr := exprs.head; BEGIN
    WHILE curr # NIL DO
      Expr(curr.expr);
      curr := curr.next;
    END
  END ExprList;

PROCEDURE ExpectedError(t: TEXT; ast: JunoAST.T)
    RAISES {JunoCompileErr.Error} =
  BEGIN
    JunoCompileErr.Raise("Expected \"" & t & "\"", ast)
  END ExpectedError;

BEGIN
END JunoChkBNF.