Guest User

Untitled

a guest
May 26th, 2018
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.80 KB | None | 0 0
  1. ;; bang-lisp is a subset of Common Lisp implementation,
  2. ;; based on the textbook, "対話によるCommon Lisp入門",
  3. ;; published from 森北出版株式会社.
  4. ;; # ISBN-10: 4627836090
  5. ;; # ISBN-13: 978-4627836099
  6. ;; Additionally, some library functions are imported from
  7. ;; Appendix B of Paul Graham's "ANSI Common Lisp".
  8. ;; # ISBN-10: 4894714337
  9. ;; # ISBN-13: 978-4894714335
  10. ;; Originally, "対話によるCommon Lisp入門" suggests to use
  11. ;; CLOS, Common Lisp Object System, to implement the subset
  12. ;; of Common Lisp; however, I do not like Object Oriented
  13. ;; Programming style; in fact, I do try that by using PLT
  14. ;; Scheme's define-struct. Therefore, this implementation
  15. ;; heavily depends on PLT Scheme in order to convert some OOP
  16. ;; idea to structures with some fun and ,also, headache.
  17. ;; Thanks to PLT to provide such a great Scheme implementation,
  18. ;; anyway.
  19. ;; People may see the topic like Scheme implemented on Scheme or
  20. ;; CL implemented on CL; however I think it must be rarely to see
  21. ;; CL implemented on Scheme and vice versa. Thus, even though this
  22. ;; is my personal lesson to understand Lisps more, it may be helpful
  23. ;; for the people, studying to implement a Common Lisp subset on
  24. ;; Scheme. It must be fun across Lisp-1 and Lisp-2, with PLT.
  25. ;; By the way, most of ! mark on this source does not related to
  26. ;; any destructive operations(some are yes, of course).
  27. ;; The way of naming procedures here just relies on the text book,
  28. ;; "対話によるCommon Lisp入門".
  29.  
  30. (module bang-lisp-ver.1.0 scheme
  31.  
  32. (provide (all-defined-out))
  33.  
  34. ;;; !Lisp 基本設定
  35.  
  36. ;; id の設定
  37. (define *new-id* 0)
  38. (define (new-id) (set! *new-id* (+ 1 *new-id*)) *new-id*)
  39.  
  40. ;; オブジェクトの生成
  41. (define-struct !object (id))
  42.  
  43. ;; 二つのオブジェクトの同値性判定
  44. (define (!eq? x y) (= (!object-id x) (!object-id y)))
  45.  
  46. ;;; 構造体によるデータ抽象
  47.  
  48. ;; 構造体によるアトムの定義
  49. (define-struct (!atom !object) ()
  50. )
  51.  
  52. ;; 構造体によるコンスの定義
  53. (define-struct (!cons !object)
  54. (first rest)
  55. )
  56.  
  57. ;; 構造体による数値の定義
  58. (define-struct (!number !atom) (number)
  59. )
  60.  
  61. ;; 構造体による文字列の定義
  62. (define-struct (!string !atom) (string)
  63. )
  64.  
  65. ;; 構造体によるシンボルの定義
  66. (define-struct (!symbol !atom)
  67. (name value function plist package)
  68. #:mutable
  69. )
  70.  
  71. ;; 構造体による NULL の定義
  72. (define-struct (!null !symbol) ()
  73. )
  74.  
  75. ;;; 構造体によるパッケージの定義
  76. (define-struct (!package !atom)
  77. (name hash)
  78. )
  79.  
  80. ;;; 構造体による関数の定義
  81. (define-struct (!function !atom) ()
  82. )
  83.  
  84. ;; 構造体による特殊オペレータの定義
  85. (define-struct (!special !function)
  86. (code)
  87. )
  88.  
  89. ;; 構造体による funcallable の定義
  90. (define-struct (!funcallable !function) ()
  91. )
  92.  
  93. ;; 構造体によるプリミティヴの定義
  94. (define-struct (!primitive !funcallable)
  95. (code)
  96. )
  97.  
  98. ;; 構造体によるクロージャの定義
  99. (define-struct (!closure !funcallable)
  100. (body parameters environment)
  101. )
  102.  
  103. ;; make-instance で構造体によるデータ型の作成(ショートカット)
  104. (define-syntax make-instance
  105. (syntax-rules
  106. (!object !atom !cons !number !string
  107. !symbol !package !special !primitive !closure)
  108. ((_ !object)
  109. (make-!object (new-id)))
  110. ((_ !atom)
  111. (make-!atom (new-id)))
  112. ((_ !cons x y)
  113. (make-!cons (new-id) x y))
  114. ((_ !number number)
  115. (make-!number (new-id) number))
  116. ((_ !string string)
  117. (make-!string (new-id) string))
  118. ((_ !symbol name value function plist package)
  119. (make-!symbol (new-id)
  120. name value function plist package))
  121. ((_ !package name hash)
  122. (make-!package (new-id)
  123. name hash))
  124. ((_ !special code)
  125. (make-!special (new-id) code))
  126. ((_ !primitive code)
  127. (make-!primitive (new-id) code))
  128. ((_ !closure body parameters environment)
  129. (make-!closure (new-id) body parameters environment))))
  130.  
  131. ;;; データ変換
  132.  
  133. ;; !Lisp のデータから PLT Scheme 上のデータへの変換
  134. (define (!CL->plt !obj)
  135. (cond ((!cons? !obj)
  136. (cons (!CL->plt (!cons-first !obj))
  137. (let ((tail (!cons-rest !obj)))
  138. (if (!null? tail)
  139. '()
  140. (!CL->plt tail)))))
  141. ((!symbol? !obj)
  142. (string->symbol (!CL->plt (!symbol-name !obj))))
  143. ((!string? !obj)
  144. (!string-string !obj))
  145. ((!number? !obj)
  146. (!number-number !obj))
  147. ((!object? !obj)
  148. !obj)
  149. (else
  150. #f)))
  151.  
  152. ;; PLT Scheme のデータから !Lisp 上のデータへの変換
  153. (define (plt->!CL obj)
  154. (cond ((pair? obj)
  155. (!cons! (plt->!CL (car obj)) (plt->!CL (cdr obj))))
  156. ((null? obj)
  157. !nil)
  158. ((symbol? obj)
  159. (!intern! (plt->!CL (string-upcase (symbol->string obj)))))
  160. ((string? obj)
  161. (make-instance !string obj))
  162. ((number? obj)
  163. (make-instance !number obj))
  164. (else
  165. #f)))
  166.  
  167. ;;; 手続き
  168.  
  169. ;; !make-symbol! の定義
  170. (define (!make-symbol! !str !pac)
  171. (make-instance !symbol !str #f #f #f !pac))
  172.  
  173. ;; null!? の定義
  174. (define (null!? !obj)
  175. (!eq? !obj !nil))
  176.  
  177. ;; !intern! の定義
  178. (define (!intern! !str (!pac !*package*))
  179. (let ((str (!string-string !str))
  180. (hash (!package-hash !pac)))
  181. (let ((!sym (hash-ref hash str #f)))
  182. (or !sym
  183. (let ((!symbol (!make-symbol! !str !pac)))
  184. (hash-set! hash str !symbol)
  185. !symbol)))))
  186.  
  187. ;; コンスの定義
  188. (define (!cons! x y)
  189. (make-instance !cons x y))
  190.  
  191. ;; 引数を評価しない手続き
  192. (define (noeval-args! !args)
  193. (let loop ((!args !args) (acc '()))
  194. (if (null!? !args)
  195. (reverse acc)
  196. (loop (!cons-rest !args)
  197. (cons (!cons-first !args) acc)))))
  198.  
  199. ;; 引数を評価する手続き
  200. (define (eval-args! !args local)
  201. (let loop ((!args !args) (acc '()))
  202. (if (null!? !args)
  203. (reverse acc)
  204. (loop (!cons-rest !args)
  205. (cons (!eval! (!cons-first !args) local) acc)))))
  206.  
  207. ;; funcall の定義
  208. (define (!funcall! !obj . args)
  209. (cond
  210. ((!closure? !obj)
  211. (!eval! (!closure-body !obj)
  212. (let ((h (!closure-environment !obj)))
  213. (for-each (lambda (key val)
  214. (hash-set! h key val))
  215. (!closure-parameters !obj)
  216. args)
  217. h)))
  218. ((!primitive? !obj)
  219. (apply (!primitive-code !obj) args))
  220. (else
  221. #f)))
  222.  
  223. ;; function の定義
  224. (define (!function! local !obj)
  225. (cond
  226. ((!cons? !obj)
  227. (make-instance !closure
  228. (!cons-first (!cons-rest (!cons-rest !obj)))
  229. (noeval-args! (!cons-first (!cons-rest !obj)))
  230. local))
  231. ((!symbol? !obj)
  232. (!symbol-function !obj))
  233. (else
  234. #f)))
  235.  
  236. ;; 外部ライブラリのロード用手続き
  237. (define (!lisp-load filename)
  238. (letrec ((!load
  239. (lambda (p)
  240. (let ((x (read p)))
  241. (cond ((eof-object? x)
  242. (close-input-port p))
  243. (else
  244. (!eval! (plt->!CL x))
  245. (!load p)))))))
  246. (call-with-input-file filename !load)))
  247.  
  248. ;;; 大域変数
  249.  
  250. ;; 大域変数としてのパッケージの定義
  251. (define !*package*
  252. (make-instance !package
  253. (plt->!CL "!CL-USER")
  254. (make-hash)))
  255.  
  256. ;; 大域変数としての nil の定義
  257.  
  258. (define !nil
  259. (make-!null (new-id)
  260. (plt->!CL "NIL")
  261. #f
  262. #f
  263. #f
  264. !*package*))
  265.  
  266. (set-!symbol-value! !nil !nil)
  267. (set-!symbol-plist! !nil !nil)
  268.  
  269. ;; 大域変数としてのパッケージの定義
  270.  
  271. (hash-set! (!package-hash !*package*) "NIL" !nil)
  272.  
  273. ;; 大域変数としての t の定義
  274. (define !t (plt->!CL 't))
  275. (set-!symbol-value! !t !t)
  276.  
  277. ;; 大域変数としての pi の定義
  278. (define !pi (plt->!CL 'pi))
  279. (set-!symbol-value! !pi (plt->!CL pi))
  280.  
  281. ;; 大域変数としての lambda の定義
  282. (define !lambda (plt->!CL 'lambda))
  283.  
  284. ;;; !Lisp 本体
  285.  
  286. ;; REPL
  287.  
  288. (define *version* "!Lisp Ver.1.0\n")
  289.  
  290. (define (!lisp)
  291. (call/cc
  292. (lambda (k)
  293. (define (repl)
  294. (print-prompt) (!print! (!eval! (!read! k))) (newline))
  295. (define (loop exp)
  296. (loop (repl)))
  297. (display *version*)
  298. (loop (repl)))))
  299.  
  300. (define (print-prompt)
  301. (display (string-append
  302. (!CL->plt (!package-name !*package*))
  303. "> ")))
  304.  
  305. (define (!read! k)
  306. (let ((exp (read)))
  307. (if (and (list? exp)
  308. (memq (car exp)
  309. '(bye quit end exit)))
  310. (k 'GOOD-BYE)
  311. (plt->!CL exp))))
  312.  
  313. (define (!print! !obj)
  314. (write (!CL->plt !obj))
  315. !obj)
  316.  
  317. ;; eval
  318. (define (!eval! !obj (local (make-hasheq)))
  319. (cond
  320. ((!cons? !obj)
  321. (!apply! (!cons-first !obj) (!cons-rest !obj) local))
  322. ((!symbol? !obj)
  323. (let ((binding (hash-ref local !obj #f)))
  324. (or binding
  325. (!symbol-value !obj))))
  326. (else
  327. !obj)))
  328.  
  329. ;; apply
  330. (define (!apply! !obj !args local)
  331. (cond
  332. ((!funcallable? !obj)
  333. (apply !funcall!
  334. (cons !obj (eval-args! !args local))))
  335. ((!special? !obj)
  336. (apply (!special-code !obj)
  337. (cons local
  338. (noeval-args! !args))))
  339. ((!symbol? !obj)
  340. (!apply! (!symbol-function !obj) !args local))
  341. (else
  342. #f)))
  343.  
  344. ;;; 特殊オペレータの定義
  345.  
  346. ;; quote の定義
  347. (define (!quote! local !a1) !a1)
  348.  
  349. ;; if の定義
  350. (define (!if! local !condition !then !else)
  351. (if (null!? (!eval! !condition local))
  352. (!eval! !else local)
  353. (!eval! !then local)))
  354.  
  355. ;; setq の定義
  356. (define (!setq! local !sym !form)
  357. (let ((!value (!eval! !form local))
  358. (binding (hash-ref local !sym #f)))
  359. (cond (binding
  360. (set! binding !value)
  361. !value)
  362. (else
  363. (set-!symbol-value! !sym !value)
  364. !value))))
  365.  
  366. ;; defun の定義
  367. (define (!defun! local !name !parameters !body)
  368. (set-!symbol-function! !name
  369. (make-instance !closure
  370. !body
  371. (noeval-args! !parameters)
  372. local))
  373. !name)
  374.  
  375. ;;; 基本関数の定義
  376.  
  377. ;; eq? の定義
  378. (define (!eq!? !x !y)
  379. (if (!eq? !x !y) !t !nil))
  380.  
  381. ;; null? の定義
  382. (define (!null!? !x) (!eq!? !x !nil))
  383.  
  384. ;; atom? の定義
  385. (define (!atom!? !x)
  386. (cond ((!atom? !x) !t)
  387. ((!null? !x) !t)
  388. (else !nil)))
  389.  
  390. ;; list? の定義
  391. (define (!list!? !x)
  392. (cond ((!cons? !x) !t)
  393. ((!null? !x) !t)
  394. (else !nil)))
  395.  
  396. ;; + の定義
  397. (define (!+! . list-of-!numbers)
  398. (plt->!CL (apply + (map !CL->plt list-of-!numbers))))
  399.  
  400. ;; - の定義
  401. (define (!-! . list-of-!numbers)
  402. (and (pair? list-of-!numbers)
  403. (plt->!CL (apply - (map !CL->plt list-of-!numbers)))))
  404.  
  405. ;; * の定義
  406. (define (!*! . list-of-!numbers)
  407. (plt->!CL (apply * (map !CL->plt list-of-!numbers))))
  408.  
  409. ;; / の定義
  410. (define (!/! . list-of-!numbers)
  411. (and (pair? list-of-!numbers)
  412. (plt->!CL (apply / (map !CL->plt list-of-!numbers)))))
  413.  
  414. ;; eval の定義
  415. (define (!eval*! !form) (!eval! !form (make-hasheq)))
  416.  
  417. ;; consp の定義
  418. (define (!cons!? !obj) (if (!cons? !obj) !t !nil))
  419.  
  420. ;; stringp の定義
  421. (define (!string!? !obj) (if (!string? !obj) !t !nil))
  422.  
  423. ;;; 各定義のインストール
  424.  
  425. ;; quote のインストール
  426. (set-!symbol-function! (plt->!CL 'quote)
  427. (make-instance !special !quote!))
  428.  
  429. ;; if のインストール
  430. (set-!symbol-function! (plt->!CL 'if)
  431. (make-instance !special !if!))
  432.  
  433. ;; setq のインストール
  434. (set-!symbol-function! (plt->!CL 'setq)
  435. (make-instance !special !setq!))
  436.  
  437. ;; eq のインストール
  438. (set-!symbol-function! (plt->!CL 'eq)
  439. (make-instance !primitive !eq!?))
  440.  
  441. ;; null のインストール
  442. (set-!symbol-function! (plt->!CL 'null)
  443. (make-instance !primitive !null!?))
  444.  
  445. ;; atom のインストール
  446. (set-!symbol-function! (plt->!CL 'atom)
  447. (make-instance !primitive !atom!?))
  448.  
  449. ;; listp のインストール
  450. (set-!symbol-function! (plt->!CL 'listp)
  451. (make-instance !primitive !list!?))
  452.  
  453. ;; + のインストール
  454. (set-!symbol-function! (plt->!CL '+)
  455. (make-instance !primitive !+!))
  456.  
  457. ;; - のインストール
  458. (set-!symbol-function! (plt->!CL '-)
  459. (make-instance !primitive !-!))
  460.  
  461. ;; * のインストール
  462. (set-!symbol-function! (plt->!CL '*)
  463. (make-instance !primitive !*!))
  464.  
  465. ;; / のインストール
  466. (set-!symbol-function! (plt->!CL '/)
  467. (make-instance !primitive !/!))
  468.  
  469. ;; first のインストール
  470. (set-!symbol-function! (plt->!CL 'first)
  471. (make-instance !primitive !cons-first))
  472.  
  473. ;; rest のインストール
  474. (set-!symbol-function! (plt->!CL 'rest)
  475. (make-instance !primitive !cons-rest))
  476.  
  477. ;; cons のインストール
  478. (set-!symbol-function! (plt->!CL 'cons)
  479. (make-instance !primitive !cons!))
  480.  
  481. ;; read のインストール
  482. (set-!symbol-function! (plt->!CL 'read)
  483. (make-instance !primitive !read!))
  484.  
  485. ;; print のインストール
  486. (set-!symbol-function! (plt->!CL 'print)
  487. (make-instance !primitive !print!))
  488.  
  489. ;; symbol-name のインストール
  490. (set-!symbol-function! (plt->!CL 'symbol-name)
  491. (make-instance !primitive !symbol-name))
  492.  
  493. ;; symbol-value のインストール
  494. (set-!symbol-function! (plt->!CL 'symbol-value)
  495. (make-instance !primitive !symbol-value))
  496.  
  497. ;; symbol-function のインストール
  498. (set-!symbol-function! (plt->!CL 'symbol-function)
  499. (make-instance !primitive !symbol-function))
  500.  
  501. ;; symbol-plist のインストール
  502. (set-!symbol-function! (plt->!CL 'symbol-plist)
  503. (make-instance !primitive !symbol-plist))
  504.  
  505. ;; symbol-package のインストール
  506. (set-!symbol-function! (plt->!CL 'symbol-package)
  507. (make-instance !primitive !symbol-package))
  508.  
  509. ;; funcall のインストール
  510. (set-!symbol-function! (plt->!CL 'funcall)
  511. (make-instance !primitive !funcall!))
  512.  
  513. ;; function のインストール
  514. (set-!symbol-function! (plt->!CL 'function)
  515. (make-instance !special !function!))
  516.  
  517. ;; defun のインストール
  518. (set-!symbol-function! (plt->!CL 'defun)
  519. (make-instance !special !defun!))
  520.  
  521. ;; eval のインストール
  522. (set-!symbol-function! (plt->!CL 'eval)
  523. (make-instance !primitive !eval*!))
  524.  
  525. ;; consp のインストール
  526. (set-!symbol-function! (plt->!CL 'consp)
  527. (make-instance !primitive !cons!?))
  528.  
  529. ;; stringp のインストール
  530. (set-!symbol-function! (plt->!CL 'stringp)
  531. (make-instance !primitive !string!?))
  532.  
  533. )
Add Comment
Please, Sign In to add comment