;; VM-Scheme
;; (c) 1996-1997 Sebastian Good
;; (c) 1997-2011 PLT Scheme Inc

;; Mostly structure definitions for VM AST nodes.

(module vmscheme mzscheme
  
  (require mzlib/unit
           mzlib/list
           mzlib/etc)

  (require syntax/zodiac-sig)

  (require "sig.rkt"
           "../sig.rkt")

  (provide vmscheme@)
  (define-unit vmscheme@
      (import compiler:library^
	      compiler:cstructs^
	      (prefix zodiac: zodiac^)
	      compiler:zlayer^
	      compiler:driver^)
      (export compiler:vmstructs^)

      ;; Block statements
      (define-struct (vm:sequence zodiac:zodiac) (vals))
      (define-struct (vm:if zodiac:zodiac) (test then else))

      ;; Tail position statements
      (define-struct (vm:void zodiac:zodiac) (val magic?))
      (define-struct (vm:return zodiac:zodiac) (val magic?))
      (define-struct (vm:tail-apply zodiac:zodiac) (closure argc prim))
      (define-struct (vm:tail-call zodiac:zodiac) (label closure set-env?))
      (define-struct (vm:continue zodiac:zodiac) ())

      ;; non-tail imperative statements
      (define-struct (vm:set! zodiac:zodiac) (vars val mode))
      (define-struct (vm:generic-args zodiac:zodiac) (closure tail? magic? prim vals))
      (define-struct (vm:register-args zodiac:zodiac) (vars vals))
      (define-struct (vm:args zodiac:zodiac) (type vals))
      (define-struct (vm:begin0-mark! zodiac:zodiac) (var val))
      (define-struct (vm:begin0-setup! zodiac:zodiac) (var))
      (define-struct (vm:syntax! zodiac:zodiac) (vars val in-mod?))

      (define-struct (vm:global-prepare zodiac:zodiac) (vec pos))
      (define-struct (vm:global-lookup zodiac:zodiac) (vec pos))
      (define-struct (vm:global-assign zodiac:zodiac) (vec val pos))
      (define-struct (vm:safe-vector-ref zodiac:zodiac) (vec pos))

      ;; r-values (1 step computations)
      (define-struct (vm:alloc zodiac:zodiac) (type))
      (define-struct (vm:build-constant zodiac:zodiac) (text))
      (define-struct (vm:make-closure zodiac:zodiac) (closure))
      (define-struct (vm:make-procedure-closure vm:make-closure)
	(vehicle min-arity max-arity name empty? method?))
      (define-struct (vm:make-case-procedure-closure vm:make-closure)
	(vehicle num-cases case-arities name empty? method?))
      (define-struct (vm:apply zodiac:zodiac) 
	(closure argc known? multi? prim simple-tail-prim?))
      (define-struct (vm:macro-apply zodiac:zodiac) 
	(name primitive args tail? magic? bool?))
      (define-struct (vm:call zodiac:zodiac) (label closure))
      (define-struct (vm:begin0-extract zodiac:zodiac) (var))
      (define-struct (vm:wcm-mark! zodiac:zodiac) (key val))
      (define-struct (vm:wcm-push! zodiac:zodiac) (var))
      (define-struct (vm:wcm-pop! zodiac:zodiac) (var))
      (define-struct (vm:wcm-remember! zodiac:zodiac) (var val))
      (define-struct (vm:wcm-extract zodiac:zodiac) (var))
      (define-struct (vm:check-global zodiac:zodiac) (var))
      (define-struct (vm:module-create zodiac:zodiac) (shape id))

      ;; a-values
      (define-struct (vm:global-varref zodiac:zodiac) (var))
      (define-struct (vm:bucket zodiac:zodiac) (var))
      (define-struct (vm:per-load-statics-table zodiac:zodiac) ())
      (define-struct (vm:cast zodiac:zodiac) (val rep)) ; last resort

      ;; l-values (locations in memory)
      (define-struct (vm:local-varref zodiac:zodiac) (var binding))
      (define-struct (vm:static-varref zodiac:zodiac) (var))
      (define-struct (vm:static-varref-from-lift vm:static-varref) (lambda))
      (define-struct (vm:per-load-static-varref vm:static-varref) ())
      (define-struct (vm:per-load-static-varref-from-lift vm:per-load-static-varref) (lambda))
      (define-struct (vm:primitive-varref zodiac:zodiac) (var))
      (define-struct (vm:symbol-varref zodiac:zodiac) (var))
      (define-struct (vm:inexact-varref zodiac:zodiac) (var))
      (define-struct (vm:struct-ref zodiac:zodiac) (field var))
      (define-struct (vm:deref zodiac:zodiac) (var))
      (define-struct (vm:ref zodiac:zodiac) (var))

      ;; immediate values
      (define-struct (vm:immediate zodiac:zodiac) (text))

      ;; defines a structure type
      ;; all structures may be indexed by number as well.
      (define-struct vm:struct-type (fields))

      (define vm:box-struct-type (make-vm:struct-type '(box)))

      ;; argument types
      (define arg-type:register 'arg-type:register)
      (define arg-type:arg 'arg-type:arg)
      (define arg-type:tail-arg 'arg-type:tail-arg)

      ;; set!-target types
      (define target-type:global 'target-type:global)
      (define target-type:lexical 'target-type:lexical)
      (define target-type:static target-type:lexical)

      ;; this is the class of statements that make control leave the block
      (define vm:control-return?
	(one-of vm:return? vm:tail-apply? vm:tail-call? vm:continue?))

      ;; Defines fixnumness in the VM Scheme.  
      ;; may change under different implementations; and will certainly
      ;; need to change as things get unwrapped...
      (define vm:fixnum?
	(lambda (n)
	  (and (exact? n) (integer? n) (< n (expt 2 30)) (> n (- (expt 2 30))))))

      ;; This function defines whether a constant must be built or not.
      ;; This functions answers #t to constants that may just appear 
      ;; as constants in VM Scheme.
      (define vm:literal-constant?
	(let ([p? (one-of (all-of number? vm:fixnum?)
			  null?
			  boolean?
			  char?
			  void?
			  undefined?)])
	  (lambda (i)
	    (p? (syntax-e (zodiac:zodiac-stx i))))))))

#|

(define vm:vm->sexp
  (lambda (ast)
    (cond
     [(vm:sequence? ast) `(sequence ,@(map vm:vm->sexp (vm:sequence-vals ast)))]
     [(vm:if? ast) `(if ,(vm:vm->sexp (vm:if-test ast))
			,(vm:vm->sexp (vm:if-then ast))
			,(vm:vm->sexp (vm:if-else ast)))]
     [(vm:void? ast) `(void ,(vm:vm->sexp (vm:void-val ast)))]
     [(vm:return? ast) `(return ,(vm:vm->sexp (vm:return-val ast)))]
     [(vm:tail-apply? ast) `(tail-apply ,(vm:vm->sexp (vm:tail-apply-closure ast))
					(argc ,(vm:tail-apply-argc ast))
					(prim ,(vm:tail-apply-prim ast)))]
     [(vm:tail-call? ast) `(tail-call ,label (set-env? ,(vm:tail-call-set-env? ast)))]
     [(vm:continue? ast) '(continue)]
     [(vm:set!? ast) `(set! ,@(map (lambda (v)
				     `(,(car v) ,(vm:vm->sexp (cdr v))))
				   (vm:set!-vars ast))
			    ,(vm:vm->sexp (vm:set!-val ast)))]
     [(vm:generic-args? ast) 
      `(generic-args (tail? ,(vm:generic-args-tail? ast))
		     (prim ,(vm:generic-args-prim ast))
		     (vals ,@(map vm:vm->sexp (vm:generic-args-vals ast))))]
     [(vm:args? ast)
      `(args (type ,(vm:args-type ast)) (vals ,@(map vm:vm->sexp (vm:args-vals ast))))]
     [(vm:struct? ast)
      (let ([super (vm:struct-super ast)])
	`(struct ,(vm:struct-type ast)
		 ,(if super (vm:vm->sexp (vm:struct-super ast)) #f)
		 ,(vm:struct-fields ast)))]
     [(vm:alloc? ast)
      `(alloc ,(rep->sexp (vm:alloc-type ast)))]
     
     [(vm:build-constant? ast)
      `(build-constant ,(zodiac:zread-object (vm:build-constant-text ast)))]
     [(vm:make-procedure-closure? ast)
      `(make-procedure-closure ,(vm:vm->sexp (vm:make-closure-closure ast))
			       ,(vm:make-closure-min-arity ast)
			       ,(vm:make-closure-max-arity ast))]
     [(vm:apply? ast)
      `(apply ,(vm:vm->sexp (vm:apply-closure ast))
	      (argc ,(vm:apply-argc ast))
	      (known? ,(vm:apply-known? ast))
	      (multi? ,(vm:apply-multi? ast))
	      (prim ,(vm:apply-prim ast)))]
     [(vm:call? ast)
      `(call ,(vm:call-label ast))]
     [(vm:global-varref? ast)
      `(global-varref ,(vm:global-varref-var ast))]
     [(vm:local-varref? ast)
      `(local-varref ,(vm:local-varref-var ast))]
     [(vm:static-varref? ast)
      `(static-varref ,(vm:static-varref-var ast))]
     [(vm:primitive-varref? ast) 
      `(primitive-varref ,(vm:primitive-varref-var ast))]
     [(vm:struct-ref? ast)
      `(struct-ref ,(vm:struct-ref-field ast)
		   ,(vm:vm->sexp (vm:struct-ref-var ast)))]
     [(vm:deref? ast)
      `(deref ,(vm:vm->sexp (vm:deref-var ast)))]
     [(vm:ref? ast)   
      `(ref ,(vm:vm->sexp (vm:ref-var ast)))] 
     [(vm:immediate? ast)
      (let ([text (vm:immediate-text ast)])
	`(immediate ,(cond [(number? text)
			    `(label ,text)]
			   [(zodiac:zread? text)
			    (zodiac:zread-object text)]
			   [else (error 'vm:vm->sexp "~a bad immediate text" text)])))]
     [else
      (error 'vm:vm->sexp "~a not supported" ast)])))
|#
