假设我正在使用s表达式作为我正在编写的语言的IR。然后我可能有一个看起来像
的AST'(add (times (3 : int)
(add (4 : int)
(5 : int)))
(1 : int))
我可以毫不费力地递归处理。例如,要删除我可以执行的类型注释
(define (erase-types term)
(match term
[`(,val : ,type)
val]
[`(,binop ,arg1 ,arg2)
`(,binop ,(erase-types arg1) ,(erase-types arg2))]))
现在假设我想做同样的事情,而是在编译时使用包含与顶部AST相同的数据的语法对象。我尝试使用某种基于模式的宏,但似乎我不能以递归方式使用(define-syntax erase-types-or-whatever ...)
。
我还尝试将一个普通的match
函数放在一个单独的模块(require (for-syntax ...))
中,并在开头做一个大的syntax->datum
,甚至做类似的事情
(define (erase-types-or-whatever stx)
(match (syntax-e stx)
[...]))
但是我到处都有syntax->datum
,我必须再次使用datum->syntax
重新构建它,我真的不知道如何使用它(我只是把#f
作为第一个参数?)而这一切只是感觉绝对错误的做法。
进行这种语法树处理的正确方法是什么?当谈到宏和语法时,文档并不是超级启发。
答案 0 :(得分:2)
#lang racket
(require syntax/parse)
(define-syntax : (λ (stx) (raise-syntax-error ': "used out of context" stx)))
(define (erase-types term)
(syntax-parse term
#:literals (:)
[(val : type) #'val]
[(binop arg1 arg2) (with-syntax ([arg1 (erase-types #'arg1)]
[arg2 (erase-types #'arg2)])
#'(binop arg1 arg2))]))
(erase-types #'(add (times (3 : int)
(add (4 : int)
(5 : int)))
(1 : int)))