etng-r2/compile-to-scheme.scm
author Tony Garnock-Jones <tonygarnockjones@gmail.com>
Wed, 16 Jan 2019 17:15:58 +0000
changeset 438 1fe179d53161
parent 278 843b43973b4c
permissions -rw-r--r--
Add missing primitive implementation for the plain interpreter.
(define previous-inspector (current-inspector))
(current-inspector (make-inspector))

(define-record-type etng-alternation
  (make-etng-alternation clauses)
  etng-alternation?
  (clauses etng-alternation-clauses))

(current-inspector previous-inspector)

;---------------------------------------------------------------------------

(define etng-namespaces '())
(define implicit-etng-namespace #f)

(define builtin-namespace-url "http://www.eighty-twenty.org/etng/r2/builtin#")

(define (set-etng-namespace! prefix url)
  (cond
   ((assq prefix etng-namespaces) =>
    (lambda (cell) (set-box! (cdr cell) url)))
   (else
    (set! etng-namespaces (cons (cons prefix (box url)) etng-namespaces)))))

(set-etng-namespace! '|| builtin-namespace-url)

(define (mangle-etng-id* url localname)
  (string->symbol (string-append "etng___" url (symbol->string localname))))

(define (mangle-etng-id id)
  (cond
   ((qname? id)
    (cond
     ((assq (qname-uri id) etng-namespaces) =>
      (lambda (entry)
	(mangle-etng-id* (unbox (cdr entry)) (qname-localname id))))
     (else
      (error 'unknown-qname-prefix id))))
   ((symbol? id)
    (if implicit-etng-namespace
	(mangle-etng-id* implicit-etng-namespace id)
	(mangle-etng-id* "" id)))
   (else (error 'invalid-etng-id id))))

(define (etng-send-via-named-proxy receiver localname message)
  (etng-send* receiver
	      (namespace-variable-value (mangle-etng-id* builtin-namespace-url localname))
	      message))

(define (etng-alternation->parser a)
  (lambda (input ks kf)
    (let loop ((clauses (etng-alternation-clauses a)))
      (if (null? clauses)
	  (kf)
	  ((car clauses) input ks (lambda () (loop (cdr clauses))))))))

(define (make-parser-invocation first-message)
  (let ((fragments-rev (make-parameter (list first-message))))
    (define (fragment-following f)
      (let search ((candidate #f)
		   (fs (fragments-rev)))
	(cond
	 ((null? fs) (error 'should-not-reach-here 'fragment-following))
	 ((eq? (car fs) f) candidate)
	 (else (search (car fs) (cdr fs))))))
    (define (remaining-input-following f)
      (let search ((acc '())
		   (fs (fragments-rev)))
	(cond
	 ((null? fs) (error 'should-not-reach-here 'fragment-following))
	 ((eq? (car fs) f) acc)
	 (else (search (append (car fs) acc) (cdr fs))))))
    (define (stream-fragment f)
      (let loop ((position f))
	(lambda (op k)
	  (case op
	    ((next)
	     (if (null? position)
		 (let ((next-fragment (fragment-following f)))
		   (if next-fragment
		       ((stream-fragment next-fragment) 'next k)
		       (let ((so-far (fragments-rev)))
			 (lambda (ignored-receiver)
			   (lambda (message)
			     (parameterize ((fragments-rev (cons message so-far)))
			       ((stream-fragment message) 'next k)))))))
		 (k (car position) (loop (cdr position)))))
	    ((rest)
	     (k (append position (remaining-input-following f))))
	    (else
	     (error 'invalid-op op))))))
    (stream-fragment first-message)))

(define (etng-lookup via message)
  (cond
   ((etng-alternation? via)
    ((etng-alternation->parser via)
     (make-parser-invocation message)
     (lambda (rhs-thunk-waiting-for-self remaining-input)
       (remaining-input 'rest
			(lambda (remaining-message)
			  (if (null? remaining-message)
			      rhs-thunk-waiting-for-self
			      (lambda (receiver)
				(etng-send (rhs-thunk-waiting-for-self receiver)
					   remaining-message))))))
     (lambda () #f)))
   ((procedure? via)
    (via message))
   (else 'invalid-via (list via message))))

(define (etng-directly-invokable? x)
  (or (procedure? x) ;; a parser-invocation, (lambda (message) ...)
      (etng-alternation? x) ;; a parser without invocation: see etng-lookup
      ))

(define (etng-send* receiver via message)
  (cond
   ((etng-directly-invokable? via)
    (let ((thunk (or (etng-lookup via message)
		     (error 'does-not-understand receiver via message))))
      (thunk receiver)))
   ((number? via) (etng-send-via-named-proxy receiver 'numberProxy message))
   ((string? via) (etng-send-via-named-proxy receiver 'stringProxy message))
   ((qname-or-symbol? via) (etng-send-via-named-proxy receiver 'symbolProxy message))
   ((vector? via) (etng-send-via-named-proxy receiver 'tupleProxy message))
   ((not via) (etng-send-via-named-proxy receiver 'falseProxy message))
   ((eq? via #t) (etng-send-via-named-proxy receiver 'trueProxy message))
   (else (error 'illegal-primitive-object receiver via message))))

(define (etng-send receiver message)
  (etng-send* receiver receiver message))

(define (etng-merge-functions f1 f2)
  (make-etng-alternation (append (etng-alternation-clauses f1) (etng-alternation-clauses f2))))

(define (compile-to-scheme ast)

  (define (schemeify tng-sexp)
    (if (pair? tng-sexp)
	(case (car tng-sexp)
	  ((paren) (map schemeify (cdr tng-sexp)))
	  (else (error 'brack-and-brace-illegal-in-scheme-assembly)))
	tng-sexp))

  (define (make-definition id val)
    `(namespace-set-variable-value! ',(mangle-etng-id id) ,val))

  (define (toplevel ast)
    (case (car ast)
      ((define-namespace) `(set-etng-namespace! ',(cadr ast) ',(caddr ast)))
      ((declare-default-namespace) `(set! implicit-etng-namespace ',(cadr ast)))
      ((define-value) (make-definition (cadr ast) (expr (caddr ast))))
      ((define-function) (make-definition (cadr ast) (expr `(function ,(caddr ast)))))
      (else (expr ast))))

  (define (expr ast)
    (case (car ast)
      ((ref) (mangle-etng-id (cadr ast)))
      ((lit) `',(cadr ast))
      ((object) `(make-etng-alternation (list ,@(map (method (cadr ast)) (cddr ast)))))
      ((function) `(make-etng-alternation (list ,@(map (method #f) (cdr ast)))))
      ((tuple) `(vector ,@(map expr (cdr ast))))
      ((send) `(etng-send ,(expr (cadr ast)) (list ,@(map expr (cddr ast)))))
      ((assemble) `(let ,(map (lambda (binding)
				`(,(car binding) ,(expr (cadr binding))))
			      (cadr ast))
		     ,(schemeify (cadr (assq 'scheme (caddr ast))))))))

  (define (pattern p on-success on-failure)
    (case (car p)
      ((discard) on-success)
      ((bind) `(let ((,(mangle-etng-id (cadr p)) _arg)) ,on-success))
      ((lit) `(if (equal? ',(cadr p) _arg)
		  ,on-success
		  ,on-failure))
      ((tuple) `(if (and (vector? _arg)
			 (= (vector-length _arg) ,(length (cdr p))))
		    ,(let ((tuple-name (gensym '_argtuple)))
		       `(let ((,tuple-name _arg))
			  ,(let match-elts ((elts (cdr p))
					    (index 0))
			     (if (null? elts)
				 on-success
				 `(let ((_arg (vector-ref ,tuple-name ,index)))
				    ,(pattern (car elts)
					      (match-elts (cdr elts) (+ index 1))
					      on-failure))))))
		    ,on-failure))))

  (define (method self-id)
    (lambda (ast)
      (let ((body (caddr ast)))
	`(lambda (_stream _kt _kf)
	   ,(let loop ((patterns (cadr ast)))
	      `(_stream 'next
			(lambda (_arg _stream)
			  ,(let* ((remaining-patterns (cdr patterns)))
			     (pattern (car patterns)
				      (if (null? remaining-patterns)
					  `(_kt (lambda (,(if self-id
							      (mangle-etng-id self-id)
							      '_self))
						  ,(expr body))
						_stream)
					  (loop remaining-patterns))
				      `(_kf))))))))))

  (toplevel ast))