function eval { (x:tree; rho:Env) :Value   forwarded };
{ eval :Exp -> Env -> Value  Note: evaluates an Expression and returns a Value}
{POST: result tag is not deferval, weak head normal form}
   var func, switch, chnl :Value; proctag:ValueClass;
begin case x^.tag of
         ident:     eval:=applyenv(rho, x^.id);
         intcon:    eval:=mkint(x^.n);
         boolcon:   eval:=mkbool(x^.b);
         charcon:   eval:=mkchar(x^.ch);
         nilcon:    eval:=mkvalue(nilval);
         emptycon:  eval:=mkvalue(emptyval);
         newchan:   eval:=mkchannel;
         lambdaexp: eval:=mkfunc(x, rho);
         application:
            begin func := eval(x^.fun, rho);
                  if func^.tag=funcval then
                     eval:=apply(func, defer(x^.aparam, rho))
                  else error('apply ~fn ')
            end;
         unexp:   eval:=U(x^.unopr, eval(x^.unarg, rho));
         binexp:  if x^.binopr=sequencesy then                  {->}
                     if x^.left^.tag = binexp then
                     begin
                        if x^.left^.binopr = inputsy then       {...?...->}
                        begin proctag:=inprocessval;
                              if x^.left^.right^.tag <> ident then
                                 error('...?~var  ');
                        end
                        else if x^.left^.binopr = outputsy then {...!...->}
                           proctag:=outprocessval
                        else error('~?/! ->...');
                        chnl:=eval(x^.left^.left,rho);
                        if chnl^.tag <> channelval then error('chan xpctd');
                        eval:=mkprocess2(proctag,
                                         chnl,x^.left^.right,x^.right,rho)
                     end
                     else error('~IO -> ...')

                  else if x^.binopr in [inputsy,outputsy] then
                     { An action is part of a process, not a Value, ?yet? }
                     { NB. an input action needs a Cont to take in-value  }
                     error('eval ? | !')

                  else if x^.binopr=conssy then { cons should not eval ... }
                       eval:=O(x^.binopr, defer(x^.left,rho),
                                          defer(x^.right,rho))
                  else eval:=O(x^.binopr, eval(x^.left,rho),   {others strict}
                                          eval(x^.right,rho));
         ifexp:
            begin switch:=eval(x^.e1, rho);
                  if switch^.tag=boolval then
                     if switch^.b then eval:=eval(x^.e2, rho)
                                  else eval:=eval(x^.e3, rho)
                  else error('if ~bool  ')
            end;
         block:   eval:=eval( x^.exp, D(x^.decs, rho))
      end {case}
      ; evals := evals + 1 { statistics }
end {eval};

procedure force { ( v :Value )  forwarded } ;
   var fv :Value;
begin if v^.tag=deferval then
         begin fv := eval( v^.e, v^.r ); v^ := fv^ {overwrite} end
end;

{\fB Evaluate an Expression. \fP}
{ Do not remove: This program is released under Gnu `copyleft' General }
{ Public Licence (GPL)    -- L.Allison, CSSE, Monash Uni., .au, 7/2004 }
