(module teachhelp mzscheme
  (require "firstorder.rkt"
           "rewrite-error-message.rkt"
           "../version-case/version-case.rkt")

  ;; We're treading in private implementation; we deserve this pain.
  (version-case
    [(and (version<= "5.2.0.900" (version))
          (version< (version) "5.2.900"))
     (begin
       (require stepper/private/shared)
       (require-for-syntax stepper/private/shared))]
    [(version<= "5.2.900" (version))
     (begin
       (require stepper/private/syntax-property)
       (require-for-syntax stepper/private/syntax-property))]
    [else
     (error 'teachhelp.rkt "Unable to cooperate with Racket ~a" (version))])

  
  (provide make-undefined-check
           make-first-order-function)

  (define (make-undefined-check check-proc tmp-id)
    (let ([set!-stx (datum->syntax-object check-proc 'set!)])
      (make-set!-transformer
       (lambda (stx)
	 (syntax-case stx ()
	   [(set! id expr)
	    (module-identifier=? (syntax set!) set!-stx)
	    (with-syntax ([tmp-id tmp-id])
	      (syntax/loc stx (set! tmp-id expr)))]
	   [(id . args)
	    (datum->syntax-object
	     check-proc
	     (cons (stepper-syntax-property
		    (datum->syntax-object
		     check-proc
		     (list check-proc 
			   (list 'quote (syntax id))
			   tmp-id))
		    'stepper-skipto
                    (append skipto/cdr
                            skipto/third))
		   (syntax args))
	     stx)]
	   [id
            (stepper-syntax-property
             (datum->syntax-object
              check-proc
              (list check-proc 
                    (list 'quote (syntax id))
                    tmp-id)
              stx)
             'stepper-skipto
             (append skipto/cdr
                     skipto/third))])))))
#;    
  (define (appropriate-use what)
    (case what
     [(constructor)
      "called with values for the structure fields"]
     [(selector) 
      "applied to a structure to get the field value"]
     [(predicate procedure)
      "applied to arguments"]))

  (define (make-first-order-function what arity orig-id app)
    (make-set!-transformer
     (make-first-order
      (lambda (stx)
	(syntax-case stx (set!)
	  [(set! . _) (raise-syntax-error 
		       #f stx #f 
		       "internal error: assignment to first-order function")]
	  [id
	   (identifier? #'id)
	   (raise-syntax-error
	    #f
	    (format "expected a function call, but there is no open parenthesis before this function")
	    stx
	    #f)]
	  [(id . rest)
	   (let ([found (length (syntax->list #'rest))])
	     (unless (= found arity)
	       (raise-syntax-error
		#f
                (argcount-error-message arity found)
		stx
		#f))
	     (datum->syntax-object
	      app
	      (list* app (datum->syntax-object orig-id (syntax-e orig-id) #'id #'id) #'rest)
	      stx stx))]))
      (syntax-local-introduce orig-id)))))
