;;; -*- Mode:LISP; Package:EH; Base:10; Readtable:ZL -*-
;;;
;;;
;;; INTERPRETER ERRORS
;;;
;;;
;;;


;; WRONG NUMBER OF ARGUMENTS TO A FUNCTION
;;
;; Raised when the number of arguments passed to a function is less than the number
;; required or more than the number allowed.  The value returned is a list of arguments
;; that has an allowable length.
;;
;; Instance variables:
;;    function
;;       A lexical closure or a FEF, the function being applied.
;;    minimum 
;;       The minimum number of arguments required by the function.
;;    maximum 
;;       The maximum number of arguments allowed by the function.
;;    arglist
;;       List of arguments to the function.
;;
;; Proceed types:
;;    :truncate-argument-list [TOO-MANY-ARGUMENTS-ERROR only]
;;       Use only the first n arguments of arglist, where n = maximum.  Returns the new
;;       argument list. 
;;    :new-argument-list >>NOT YET IMPLEMENTED
;;       Use a new argument list composed by evaluating forms typed by the user.  Returns
;;       the new argument list.
;;    :new-value
;;       From proceed-with-value-mixin.  Prompts the user for an expression to evaluate
;;       in place of the function application, and returns the expression.
	 
(defflavor INTERPRETER::GET-NEW-ARG-LIST-MIXIN () ()
  (:required-flavors error)
  :abstract-flavor
  (:method-combination (:case :base-flavor-last
			 :proceed
			 :proceed-asking-user
			 :document-proceed-type)))

(defmethod (interpreter::get-new-arg-list-mixin :case :proceed-asking-user :new-argument-list)
	   (continuation read-object-function)
  (declare (ignore continuation read-object-function))
  (error "whoops"))

(defmethod (interpreter::get-new-arg-list-mixin :case :document-proceed-type :new-argument-list)
	   (stream &optional ignore)
  (format stream
	  "Try again with new arguments.  You type expressions for them."))


(defflavor INTERPRETER::TOO-FEW-ARGUMENTS-ERROR
	   (function minimum maximum arglist)
	   (new-proceed-with-value-mixin error)
  :inittable-instance-variables
  :gettable-instance-variables)

(defmethod (interpreter::too-few-arguments-error :report) (stream)
  (format stream
	  "Function ~S called with too few arguments; ~S provided, ~S required."
	  (interpreter::name-of-closure function)
	  (length arglist)
	  minimum))


(defflavor INTERPRETER::TOO-MANY-ARGUMENTS-ERROR
	   (function minimum maximum arglist)
	   (new-proceed-with-value-mixin error)
  :inittable-instance-variables
  :gettable-instance-variables)

(defmethod (interpreter::too-many-arguments-error :report) (stream)
  (format stream 
	  "Function ~S called with too many arguments; ~S allowed, ~S provided."
	  (interpreter::name-of-closure function)
	  maximum
	  (length arglist)))

(defmethod (interpreter::too-many-arguments-error 
	     :case :proceed-asking-user :truncate-argument-list)
	   (continuation ignore)
  (send continuation 
	:truncate-argument-list (ldiff arglist (nthcdr maximum arglist))))

(defmethod (interpreter::too-many-arguments-error
	     :case :document-proceed-type :truncate-argument-list)
	   (stream &optional ignore)
  (format stream
	  "Apply the function again, dropping all but the first ~S argument~:P."
	  maximum))



;; PROCEED-WITH-VALUE MIXIN
;;
;; Proceed types:
;;    :new-value
;;        Prompts the user for an expression to evaluate, then returns it.

(defflavor new-proceed-with-value-mixin () ()
  (:required-flavors error)
  :abstract-flavor
  (:method-combination (:case :base-flavor-last
			 :proceed
			 :proceed-asking-user
			 :document-proceed-type)))

(defmethod (new-proceed-with-value-mixin :case :proceed-asking-user :new-value)
	   (continuation read-object-function)
  ; this is superseded by the :document-proceed-type 
  ; "Returns a value, the value of an expression typed."
  ;
  ; The :eval-read should become a :read with an explicit eval to allow
  ; for the lexical environment
  (send continuation 
	:new-value (send read-object-function 
			 :eval-read "Form (NEW!) to evaluate and use: ")))

(defmethod (new-proceed-with-value-mixin :case :document-proceed-type :new-value)
	   (stream &optional ignore)
  (format stream
	  "Evaluate an expression you type, and use its value."))
  

;; EVALUATING A FREE VARIABLE
;;
;; Raised when an attempt is made to evaluate a free variable which has not been declared
;; special.  The value returned is used as the value of the free variable.
;;
;; Instance variables:
;;    symbol  
;;       The symbol for the free variable.
;;
;; Proceed types:
;;    :new-value
;;       From proceed-with-value-mixin.  Prompts the user for a value, and returns it.
;;    :use-dynamic-value
;;       Use the dynamic value of the free variable.  A warning is made in advance if the
;;       dynamic value is unbound.  Returns the dynamic value.
;;    :make-special
;;       Proclaim the variable to be special and returns its dynamic value.  A warning
;;       is made in advance if the dynamic value is unbound.

(defflavor INTERPRETER::EVAL-FREE-VARIABLE-ERROR (symbol attempt)
	   (new-proceed-with-value-mixin error)
  :inittable-instance-variables
  :gettable-instance-variables)

(defmethod (interpreter::eval-free-variable-error :report) 
	   (stream)
  (format stream 
	  "Attempt to evaluate the free variable ~S."
	  symbol)
  (format stream
	  "~&~S has no lexical binding and has not been declared special."
	  symbol))

(defmethod (interpreter::eval-free-variable-error :case :proceed-asking-user :use-dynamic-value)
	   (continuation ignore)
  "FOO"
  (funcall continuation :use-dynamic-value))

(defmethod (interpreter::eval-free-variable-error :case :document-proceed-type :use-dynamic-value)
	   (stream &optional ignore)
  (format stream 
	  "Use the dynamic (special) value of ~S.~@[  (Which is unbound!!)~]"
	  symbol
	  (not (boundp symbol))))

(defmethod (interpreter::eval-free-variable-error :case :proceed-asking-user :make-special)
	   (continuation ignore)
  (funcall continuation :make-special))

(defmethod (interpreter::eval-free-variable-error :case :document-proceed-type :make-special)
	   (stream &optional ignore)
  (format stream
	  "Proclaim ~S to be special, and use its dynamic (special) value.~@[  (Which is unbound!!)~]"
	  symbol
	  (not (boundp symbol))))
