package jscheme;

/** Holds a string representation of some Scheme code in <TT>CODE</tt>.
 * A string is better than a file because with no files, its easier to
 * compress everything in the classes.jar file. For editing convenience,
 * the following two perl convert from normal text to this Java quoted
 * format and back again:
 * <pre>
 * perl -pe 's/"/\\"/g; s/(\s*)(.*?)(\s*)$/\1"\2\\n" +\n/'
 * perl -pe 's/\\"/"/g; s/^(\s*)"/\1/; s/\\n" [+]//'
 * </pre>
 * @author Peter Norvig, peter@norvig.com http://www.norvig.com
 * Copyright 1998 Peter Norvig, see http://www.norvig.com/license.html  **/
public class SchemePrimitives {

  public static final String CODE =
"(define call/cc    call-with-current-continuation)\n" +
"(define first 	   car)\n" +
"(define second     cadr)\n" +
"(define third      caddr)\n" +
"(define rest 	   cdr)\n" +
"(define set-first! set-car!)\n" +
"(define set-rest!  set-cdr!)\n" +

//;;;;;;;;;;;;;;;; Standard Scheme Macros

"(define or\n" +
  "(macro args\n" +
    "(if (null? args)\n" +
        "#f\n" +
        "(cons 'cond (map list args)))))\n" +

"(define and\n" +
  "(macro args\n" +
    "(cond ((null? args) #t)\n" +
          "((null? (rest args)) (first args))\n" +
          "(else (list 'if (first args) (cons 'and (rest args)) #f)))))\n" +

"(define quasiquote\n" +
  "(macro (x)\n" +
    "(define (constant? exp)\n" +
      "(if (pair? exp) (eq? (car exp) 'quote) (not (symbol? exp))))\n" +
    "(define (combine-skeletons left right exp)\n" +
      "(cond\n" +
       "((and (constant? left) (constant? right))\n" +
        "(if (and (eqv? (eval left) (car exp))\n" +
                 "(eqv? (eval right) (cdr exp)))\n" +
            "(list 'quote exp)\n" +
            "(list 'quote (cons (eval left) (eval right)))))\n" +
       "((null? right) (list 'list left))\n" +
       "((and (pair? right) (eq? (car right) 'list))\n" +
        "(cons 'list (cons left (cdr right))))\n" +
       "(else (list 'cons left right))))\n" +
    "(define (expand-quasiquote exp nesting)\n" +
      "(cond\n" +
       "((vector? exp)\n" +
        "(list 'apply 'vector (expand-quasiquote (vector->list exp) nesting)))\n" +
       "((not (pair? exp))\n" +
        "(if (constant? exp) exp (list 'quote exp)))\n" +
       "((and (eq? (car exp) 'unquote) (= (length exp) 2))\n" +
        "(if (= nesting 0)\n" +
            "(second exp)\n" +
            "(combine-skeletons ''unquote\n" +
                               "(expand-quasiquote (cdr exp) (- nesting 1))\n" +
                               "exp)))\n" +
       "((and (eq? (car exp) 'quasiquote) (= (length exp) 2))\n" +
        "(combine-skeletons ''quasiquote\n" +
                           "(expand-quasiquote (cdr exp) (+ nesting 1))\n" +
                           "exp))\n" +
       "((and (pair? (car exp))\n" +
             "(eq? (caar exp) 'unquote-splicing)\n" +
             "(= (length (car exp)) 2))\n" +
        "(if (= nesting 0)\n" +
            "(list 'append (second (first exp))\n" +
                  "(expand-quasiquote (cdr exp) nesting))\n" +
            "(combine-skeletons (expand-quasiquote (car exp) (- nesting 1))\n" +
                               "(expand-quasiquote (cdr exp) nesting)\n" +
                               "exp)))\n" +
       "(else (combine-skeletons (expand-quasiquote (car exp) nesting)\n" +
                                "(expand-quasiquote (cdr exp) nesting)\n" +
                                "exp))))\n" +
    "(expand-quasiquote x 0)))\n" +

"\n" +
"(define let\n" +
  "(macro (bindings . body)\n" +
    "(define (named-let name bindings body)\n" +
      "`(let ((,name #f))\n" +
         "(set! ,name (lambda ,(map first bindings) . ,body))\n" +
         "(,name . ,(map second bindings))))\n" +
    "(if (symbol? bindings)\n" +
        "(named-let bindings (first body) (rest body))\n" +
        "`((lambda ,(map first bindings) . ,body) . ,(map second bindings)))))\n" +

"(define let*\n" +
  "(macro (bindings . body)\n" +
    "(if (null? bindings) `((lambda () . ,body))\n" +
        "`(let (,(first bindings))\n" +
           "(let* ,(rest bindings) . ,body)))))\n" +

"(define letrec\n" +
  "(macro (bindings . body)\n" +
    "(let ((vars (map first bindings))\n" +
          "(vals (map second bindings)))\n" +
    "`(let ,(map (lambda (var) `(,var #f)) vars)\n" +
       ",@(map (lambda (var val) `(set! ,var ,val)) vars vals)\n" +
       ". ,body))))\n" +

"(define case\n" +
  "(macro (exp . cases)\n" +
    "(define (do-case case)\n" +
      "(cond ((not (pair? case)) (error \"bad syntax in case\" case))\n" +
            "((eq? (first case) 'else) case)\n" +
            "(else `((member __exp__ ',(first case)) . ,(rest case)))))\n" +
    "`(let ((__exp__ ,exp)) (cond . ,(map do-case cases)))))\n" +

"(define do\n" +
  "(macro (bindings test-and-result . body)\n" +
    "(let ((variables (map first bindings))\n" +
          "(inits (map second bindings))\n" +
          "(steps (map (lambda (clause)\n" +
                        "(if (null? (cddr clause))\n" +
                            "(first clause)\n" +
                            "(third clause)))\n" +
                      "bindings))\n" +
          "(test (first test-and-result))\n" +
          "(result (rest test-and-result)))\n" +
      "`(letrec ((__loop__\n" +
                 "(lambda ,variables\n" +
                   "(if ,test\n" +
                       "(begin . ,result)\n" +
                       "(begin\n" +
                         ",@body\n" +
                         "(__loop__ . ,steps))))))\n" +
         "(__loop__ . ,inits)))))\n" +

"(define delay\n" +
  "(macro (exp)\n" +
    "(define (make-promise proc)\n" +
      "(let ((result-ready? #f)\n" +
            "(result #f))\n" +
        "(lambda ()\n" +
          "(if result-ready?\n" +
              "result\n" +
              "(let ((x (proc)))\n" +
                "(if result-ready?\n" +
                    "result\n" +
                    "(begin (set! result-ready? #t)\n" +
                           "(set! result x)\n" +
                           "result)))))))\n" +
    "`(,make-promise (lambda () ,exp))))\n" +

//;;;;;;;;;;;;;;;; Extensions

"(define time\n" +
  "(macro (exp . rest) `(time-call (lambda () ,exp) . ,rest)))\n"
;
}
