Arcの中を見る
arc.arcにdefの定義と、=マクロの定義がある。どちらも最終的にはsetを呼んでいる。defはすでにある名前だと警告を表示する(何で出なかったんだろう)。safesetからsetが呼ばれ、=は単にsetになっている。
(set safeset (annotate 'mac (fn (var val) `(do (if (bound ',var) (do (disp "*** redefining ") (disp ',var) (writec #\newline))) (set ,var ,val))))) (set def (annotate 'mac (fn (name parms . body) `(do (sref sig ',parms ',name) (safeset ,name (fn ,parms ,@body))))))
(def expand= (place val) (if (isa place 'sym) `(set ,place ,val) (let (vars prev setter) (setforms place) (w/uniq g `(atwith ,(+ vars (list g val)) (,setter ,g)))))) (def expand=list (terms) `(do ,@(map (fn ((p v)) (expand= p v)) ; [apply expand= _] (pair terms)))) (mac = args (expand=list args))
arcの本体はac.scm。arc中のbuiltinは、この中でxdefで定義されている。
(define (xdef a b) (namespace-set-variable-value! (ac-global-name a) b) b)
(xdef 'cons cons) (xdef 'car (lambda (x) (cond ((pair? x) (car x)) ((eqv? x 'nil) 'nil) ((eqv? x '()) 'nil) (#t (err "Can't take car of" x))))) (xdef 'cdr (lambda (x) (cond ((pair? x) (cdr x)) ((eqv? x 'nil) 'nil) ((eqv? x '()) 'nil) (#t (err "Can't take cdr of" x)))))
インタプリタの本体はac。トップレベルas.scmからのコールでは、(tl => tl2もしくはaload => aload1) => arc-eval => acという感じでたどり着く。
(define (ac s env) (cond ((string? s) (string-copy s)) ; to avoid immutable strings ((literal? s) s) ((eqv? s 'nil) (list 'quote 'nil)) ((ssyntax? s) (ac (expand-ssyntax s) env)) ((symbol? s) (ac-var-ref s env)) ((ssyntax? (xcar s)) (ac (cons (expand-ssyntax (car s)) (cdr s)) env)) ((eq? (xcar s) 'quote) (list 'quote (ac-niltree (cadr s)))) ((eq? (xcar s) 'quasiquote) (ac-qq (cadr s) env)) ((eq? (xcar s) 'if) (ac-if (cdr s) env)) ((eq? (xcar s) 'fn) (ac-fn (cadr s) (cddr s) env)) ((eq? (xcar s) 'set) (ac-set (cdr s) env)) ; this line could be removed without changing semantics ((eq? (xcar (xcar s)) 'compose) (ac (decompose (cdar s) (cdr s)) env)) ((pair? s) (ac-call (car s) (cdr s) env)) (#t (err "Bad object in expression" s))))
ac-callが関数よびだし
(define (ac-call fn args env) (let ((macfn (ac-macro? fn))) (cond (macfn (ac-mac-call macfn args env)) ((and (pair? fn) (eqv? (car fn) 'fn)) `(,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) ((= (length args) 0) `(ar-funcall0 ,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) ((= (length args) 1) `(ar-funcall1 ,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) ((= (length args) 2) `(ar-funcall2 ,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) ((= (length args) 3) `(ar-funcall3 ,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) ((= (length args) 4) `(ar-funcall4 ,(ac fn env) ,@(map (lambda (x) (ac x env)) args))) (#t `(ar-apply ,(ac fn env) (list ,@(map (lambda (x) (ac x env)) args)))))))
先にひっかかったリストに整数を渡すと返す処理はar-applyに入っていた。
(define (ar-apply fn args) (cond ((procedure? fn) (apply fn args)) ((pair? fn) (list-ref fn (car args))) ((string? fn) (string-ref fn (car args))) ((hash-table? fn) (ar-nill (hash-table-get fn (car args) #f))) ; experiment: means e.g. [1] is a constant fn ; ((or (number? fn) (symbol? fn)) fn) ; another possibility: constant in functional pos means it gets ; passed to the first arg, i.e. ('kids item) means (item 'kids). (#t (err "Function call on inappropriate object" fn args))))