我正在写scheme-langserver的一个核心功能,它要求快速识别宏展开前后s-expression的对应关系,场景如下。
;;a try-except s-expression to handle possible exceptions
(try
;;some works
todo
;;to catch exception c
(except c
;; a branch to handle
[else c])
对于以上代码,在LSP(language server protocol)支持的IDE场景下,我们经常希望识别branch
里面的c
,把它和except
后面的c
做一个关联。因为显然后者是try-except
结构捕捉到的一个异常,而前者是对这个异常的调用。这个关联可以用于goto-definition等操作,即当用户想要寻找branch
里面的c
的时候,IDE把except
后面那个c
突显(高亮等)出来。
很多情况下,待处理的宏往往是用户自定义如下:
(define-syntax try
(lambda (x)
(syntax-case x (except)
[(try body0 body1 ... (except condition clause0 clause1 ...))
#`((call/1cc
(lambda (escape)
(with-exception-handler
(lambda (c)
(let ([condition c]) ;; clauses may set! this
#,(let loop ([first #'clause0] [rest #'(clause1 ...)])
(if (null? rest)
(syntax-case first (else =>)
[(else h0 h1 ...) #'(escape (lambda () h0 h1 ...))]
[(tst) #'(let ([t tst]) (if t (escape (lambda () t)) (raise c)))]
[(tst => l) #'(let ([t tst]) (if t (escape (lambda () (l t))) (raise c)))]
[(tst h0 h1 ...) #'(if tst (escape (lambda () h0 h1 ...)) (raise c))])
(syntax-case first (=>)
[(tst) #`(let ([t tst]) (if t (escape (lambda () t)) #,(loop (car rest) (cdr rest))))]
[(tst => l) #`(let ([t tst]) (if t (escape (lambda () (l t))) #,(loop (car rest) (cdr rest))))]
[(tst h0 h1 ...) #`(if tst (escape (lambda () h0 h1 ...)) #,(loop (car rest) (cdr rest)))])))))
(lambda ()
;; cater for multiple return values
(call-with-values
(lambda () body0 body1 ...)
(lambda args
(escape (lambda ()
(apply values args))))))))))])))
我可以获得宏展开以后的结果如下:
((call/1cc
(lambda (escape)
(with-exception-handler
(lambda (c) (let ([c c]) (escape (lambda () c))))
(lambda ()
(call-with-values
(lambda () todo)
(lambda args (escape (lambda () (apply values args))))))))))
难题:我现在已经实现了一个分析的程序,但是效率比较低,程序比较复杂。能否使用scheme本身的一些函数和机制优化?