git.fiddlerwoaroof.com
Raw Blame History
;;; This is the parser for interface files.

(define (parse-tokens/interface tokens)
  (init-token-stream tokens)
  (let ((interface (token-case
		    (|interface| (parse-interface))
		    (|module| (interface-required-error))
		    (else (crud-in-interface-error)))))
    (cons interface (parse-interface-list))))

(define (interface-required-error)
  (parser-error 'interface-required "Expecting `interface' keyword"))

(define (crud-in-interface-error)
  (parser-error 'unexpected-interface-crud "Junk after interface"))

(define (parse-interface-list)
  (token-case
   (|interface|
     (let ((interface (parse-interface)))
       (cons interface (parse-interface-list))))
   (|module| (interface-required-error))
   (eof '())
   (else (crud-in-interface-error))))

(define (parse-interface)
  (token-case
   (modid
    (let ((module-name (token->symbol)))
      (require-token |where|
       (signal-missing-token "`where'" "interface definition"))
      (let ((mod-ast (make module (name module-name)
			          (type 'interface)
				  (exports '()))))
	(start-layout (lambda (in-layout?)
		       (parse-interface-decls mod-ast in-layout? 'import))))))))

(define (parse-interface-decls mod-ast in-layout? state)
  (token-case
    (|import| (let ((import (parse-import)))
		(when (not (eq? (import-decl-mode import) 'by-name))
		   (phase-error 'illegal-import
    "Imports in interfaces must specify specific entities"))
		(if (eq? state 'import)
		    (push-decl-list import (module-imports mod-ast))
		    (signal-misplaced-import)))
	      (terminate-interface-topdecl mod-ast in-layout? state))
    (|infix| (terminate-interface-topdecl mod-ast in-layout?
			       (parse-fixity 'n mod-ast state)))
    (|infixl| (terminate-interface-topdecl mod-ast in-layout?
			       (parse-fixity 'l mod-ast state)))
    (|infixr| (terminate-interface-topdecl mod-ast in-layout?
			       (parse-fixity 'r mod-ast state)))
    (|data| (let ((data-decl (parse-type-decl '#t)))
	      (push-decl-list data-decl (module-algdatas mod-ast)))
	    (terminate-interface-topdecl mod-ast in-layout? 'topdecl))
    (|type| (let ((synonym-decl (parse-synonym-decl)))
	     (push-decl-list synonym-decl (module-synonyms mod-ast)))
	    (terminate-interface-topdecl mod-ast in-layout? 'topdecl))
    (|class| (let ((class-decl (parse-class-decl)))
	       (check-class-default-decls class-decl)
	       (push-decl-list class-decl (module-classes mod-ast)))
	     (terminate-interface-topdecl mod-ast in-layout? 'topdecl))
    (|instance| (let ((instance-decl (parse-instance-decl '#t)))
		  (push-decl-list instance-decl (module-instances mod-ast)))
		(terminate-interface-topdecl mod-ast in-layout? 'topdecl))
    (var (let ((decl (parse-signdecl)))
	   (setf (module-decls mod-ast)
		 (decl-push decl (module-decls mod-ast))))
	 (terminate-interface-topdecl mod-ast in-layout? 'topdecl))
    ((begin-annotation no-advance)
     (let ((annotations (parse-annotations)))
       (setf (module-annotations mod-ast)
	     (append (module-annotations mod-ast) annotations)))
     (terminate-interface-topdecl mod-ast in-layout? state))
    (else
     (maybe-end-interface mod-ast in-layout?))))

(define (maybe-end-interface mod-ast in-layout?)
  (cond ((or (eq-token? '|interface|) (eq-token? 'eof) (eq-token? '\})
	     (eq-token? '$\}))
	 (close-layout in-layout?)
	 (wrapup-module mod-ast)
	 mod-ast)
	(else
	 (signal-invalid-syntax "a topdecl"))))

(define (terminate-interface-topdecl mod-ast in-layout? state)
  (token-case
   (\; (parse-interface-decls mod-ast in-layout? state))
   (else (maybe-end-interface mod-ast in-layout?))))

(define (check-class-default-decls class-decl)
  (dolist (d (class-decl-decls class-decl))
    (when (valdef? d)
      (remember-context d
       (recoverable-error 'no-defaults-in-interface
         "Class defaults should not be put in interface files")))))