public class SL_CallNode extends ParseNode {
  // child 0: identifier (name of function to call) 
  // child 1...n: expression (passed arguments)

  public int getType() { return G_CALL; }
  public ParseNode interpret(SymbolTable st) throws InterpretException {
      
      // check: function name resides in symbol table bound to 'function' type 
      String functionName = ((SL_IdentNode) getChild(0)).getName();

      if (st.getBinding(functionName).getType() != G_FUNCTION) 
	throw new InterpretException("Tried to call non-function "+functionName);
      
      // check that # of arguments == # of formal parameters of function
      SL_FunctionNode fnode = (SL_FunctionNode) st.getBinding(functionName);
      SL_BlockNode body = (SL_BlockNode) fnode.getBody(); 
      int nFormalParams = fnode.numArgs();
      int nArguments = numChildren()-1;
      if (nFormalParams != nArguments)
	throw new InterpretException("Expected "+
				     (new Integer(nFormalParams)).toString()+
				     " arguments to "+functionName+" but saw "+
				     (new Integer(nArguments)).toString());
      
      // inherit 'global' symbol table (with identifiers in new table all bound to null)
      SymbolTable stLocal = new SymbolTable(st);

      // fill in bindings for formal parameters
      for (int c=1; c<numChildren(); c++) {
	SL_ExprNode child = (SL_ExprNode) getChild(c);
	SL_NumberNode value = (SL_NumberNode) child.interpret(st);
	String formalParam = fnode.getArgument(c-1);
	stLocal.insertLexeme(formalParam);
	stLocal.setBinding(formalParam, value);
      }
     
      // interpret function 
      ParseNode returnValue=null; 
      try  { returnValue=body.interpret(stLocal); }
      catch (ReturnException r) { returnValue=r.getValue();  }
      catch (BreakException b) {  
	throw new InterpretException("Encountered 'break' outside of while block");
      }
      catch (InterpretException i) {
	// intercept the exception so we can add this function to the call stack
	i.addToCallStack(functionName);
	throw i;
      }
      return returnValue;
  }
}
