在Racket中,我可以递归地处理语法对象,就像我对s表达式一样吗?

时间:2015-09-25 22:22:19

标签: recursion racket abstract-syntax-tree

假设我正在使用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作为第一个参数?)而这一切只是感觉绝对错误的做法。

进行这种语法树处理的正确方法是什么?当谈到宏和语法时,文档并不是超级启发。

1 个答案:

答案 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)))