EoPL 読んでた記録の確認とその記録 (4)
標題をいい加減何とかしないと、と思いつつ。
とりあえず、
- abstract syntax の定義
- parse-expression の定義
- unparse-expression の定義
を作ってみます。
実装でっちあげてみました
とりあえず、ということで。元気が残ってれば試験も書きます。
abstract syntax の定義 (lexical-address.scm)
(define-datatype lexical-address lexical-address? (lit-exp (datum number?)) (lex-info (id symbol?) (depth number?) (position number?)) (free-info (id symbol?)) (if-exp (test-exp lexical-address?) (true-exp lexical-address?) (false-exp lexical-address?)) (lambda-exp (id symbol?) (body lexical-address?)) (app-exp (rator lexical-address?) (rand lexical-address?)))
parse-expression の定義 (parse-expression.scm)
(define get-position (lambda (sym l) (let inner ((sym sym) (l l) (p 0)) (cond ((null? l) #f) ((eqv? sym (car l)) p) (else (inner sym (cdr l) (+ 1 p))))))) (define get-lexical-address (lambda (symbol dict) (let inner ((symbol symbol) (dict dict) (d 0) (p 0)) (if (null? dict) (free-info symbol) (let ((pos (get-position symbol (car dict)))) (if (eqv? pos #f) (inner symbol (cdr dict) (+ 1 d) 0) (lex-info symbol d pos))))))) (define parse-expression (lambda (datum) (let inner ((datum datum) (dict '())) (cond ((number? datum) (lit-exp datum)) ((symbol? datum) (get-lexical-address datum dict)) ((pair? datum) (cond ((eqv? (car datum) 'lambda) (lambda-exp (cadr datum) (inner (caddr datum) (cons (cadr datum) dict)))) ((eqv? (car datum) 'if) (if-exp (inner (car datum) dict) (inner (cadr datum) dict) (inner (caddr datum) dict))) (else (app-exp (inner (car datum) dict) (inner (cadr datum) dict))))) (else (eopl:error 'parse-expression "Invalid concrete syntax ~s" datum))))))
unparse-expression の定義 (unparse-expression.scm)
(define unparse-expression (lambda (exp) (cases lexical-address exp (lit-exp (datum) datum) (lex-info (id depth position) id) (free-info (id) id) (lambda-exp (id body) (list 'lambda (list id) (unparse-expression body))) (if-exp (test-exp true-exp false) (list 'if (unparse-expression test-exp) (unparse-expression true-exp) (unparse-expression false-exp))) (app-exp (rator rand) (list (unparse-expression rator) (unparse-expression rand))))))
試験作成に着手。とりあえず parse-expression からなのかな。
順に検討しつつ実装
してみることに。parse-expression の試験から。とりあえず上記の定義で
(test* "lambda expression" '(lambda-exp (x) 1) (parse-expression '(lambda (x) 1)))
な試験にパスしてません。
test lambda expression, expects (lambda-exp (x) 1) ==> ERROR: GOT #<<error> "lambda-exp \"~n Bad ~a field (~s ~s) ==> #f.\" id symbol? (x)">
と思ったら色々ボケてて lexical-address.scm の lambda-exp な定義は以下で
(lambda-exp (args list?) (body lexical-address?))
lambda-expression な試験は以下ですね。
(test* "lambda expression" '(lambda-exp (x) (lit-exp 1)) (parse-expression '(lambda (x) 1)))
とりあえず現時点で試験パス。
その後
云々してて現状以下なカンジです。
(define get-position (lambda (sym l) (let inner ((sym sym) (l l) (p 0)) (cond ((null? l) #f) ((eqv? sym (car l)) p) (else (inner sym (cdr l) (+ 1 p))))))) (define get-lexical-address (lambda (symbol dict) (let inner ((symbol symbol) (dict dict) (d 0) (p 0)) (if (null? dict) (free-info symbol) (let ((pos (get-position symbol (car dict)))) (if (eqv? pos #f) (inner symbol (cdr dict) (+ 1 d) 0) (lex-info symbol d pos))))))) (define parse-expression (lambda (datum) (let inner ((datum datum) (dict '())) (cond ((null? datum) '()) ((number? datum) (lit-exp datum)) ((symbol? datum) (get-lexical-address datum dict)) ((pair? datum) (cond ((eqv? (car datum) 'lambda) (lambda-exp (cadr datum) (inner (caddr datum) (cons (cadr datum) dict)))) ((eqv? (car datum) 'if) (if-exp (inner (cadr datum) dict) (inner (caddr datum) dict) (inner (cadddr datum) dict))) (else (app-exp (inner (car datum) dict) (if (null? (cddr datum)) (inner (cadr datum) dict) (inner (cddr datum) dict)))))) (else (eopl:error 'parse-expression "Invalid concrete syntax ~s" datum))))))
試験が以下。
(use gauche.test) (add-load-path ".") (load "parse-expression") (test-start "parse-expression") (test-section "parse-expression") (test* "number?" '(lit-exp 5) (parse-expression 5)) (test* "free-var" '(free-info x) (parse-expression 'x)) (test* "lambda expression" '(lambda-exp (x) (lit-exp 1)) (parse-expression '(lambda (x) 1))) (test* "if expression" '(if-exp (app-exp (free-info null?) (free-info l)) (lit-exp 1) (lit-exp 2)) (parse-expression '(if (null? l) 1 2))) (test-end)
上記はパスしてるのですが以下が駄目。
(test* "if expression more" '(if-exp (app-exp (free-info =) (free-info x) (lit-exp 1)) (free-info x) (lit-exp 1)) (parse-expression '(if (= x 1) x 1)))
もう少し頑張ってみようと思いますが今日はもう限界かも。以下なあたりがアレ。
(else (app-exp (inner (car datum) dict) (if (null? (cddr datum)) (inner (cadr datum) dict) (inner (cddr datum) dict))))))
来週も稼動空きがあるんですが大丈夫なのかorz