12.4 구문 트랜스포머

12.4 구문 트랜스포머 (Syntax Transformers)

이 섹션은 매크로 확장기를 직접 다루는 절차와 형식들을 다뤄요. set!과 협력하는 할당 트랜스포머, 식별자를 다른 식별자로 대체하는 리네임 트랜스포머, 확장을 통제하는 local-expand, require·provide를 변형하는 트랜스포머, 그리고 지연된(portal) 구문까지 폭넓게 설명해요.

출처: Racket Reference

본문

set! 트랜스포머 (Set!-Transformers)

procedure

(set!-transformer? v) → boolean?
  v : any/c

vmake-set!-transformer가 만든 값이거나 prop:set!-transformer 속성을 가진 구조체 타입의 인스턴스이면 #t, 그 외에는 #f를 반환해요.

procedure

(make-set!-transformer proc) → set!-transformer?
  proc : (syntax? . -> . syntax?)

set!과 협력하는 **할당 트랜스포머(assignment transformer)**를 만들어요. make-set!-transformer의 결과가 트랜스포머 바인딩으로 id에 바인딩되면, id가 표현식 위치에서 쓰이거나 (set! id expr)처럼 set! 할당의 대상으로 쓰일 때 proc이 트랜스포머로 적용돼요. 식별자가 set! 대상으로 나타나면, 트랜스포머에게 set! 표현식 전체가 제공돼요.

예:

> (let ([x 1]
        [y 2])
    (let-syntax ([x (make-set!-transformer
                     (lambda (stx)
                       (syntax-case stx (set!)
                         ; Redirect mutation of x to y
                         [(set! id v) #'(set! y v)]
                         ; Normal use of x really gets x
                         [id (identifier? #'id) #'x])))])
      (begin
        (set! x 3)
        (list x y))))
'(1 3)

procedure

(set!-transformer-procedure transformer)
  → (syntax? . -> . syntax?)
  transformer : set!-transformer?

transformer를 만들기 위해 make-set!-transformer에 전달되었거나 transformerprop:set!-transformer 속성이 지정하는 프로시저를 반환해요.

value

prop:set!-transformer : struct-type-property?

make-set!-transformer가 만든 것 같은 할당 트랜스포머 역할을 하는 구조체 타입을 식별하는 구조체 타입 속성이에요.

속성 값은 정확한 정수 또는 인자 하나 또는 둘을 받는 프로시저여야 해요. 전자의 경우 정수는 구조체 안에서 프로시저를 담아야 할 필드를 지정하며, 정수는 0(포함)과 구조체 타입의 비자동 필드 수(배타, 슈퍼타입 필드는 세지 않음) 사이여야 하고, 지정된 필드는 불변으로도 지정되어야 해요.

속성 값이 인자 하나짜리 프로시저이면 그 프로시저가 구문 트랜스포머이자 set! 변환 역할을 해요. 속성 값이 인자 둘짜리 프로시저이면, 첫 인자는 prop:set!-transformer 속성을 가진 타입의 구조체이고 두 번째 인자는 구문 트랜스포머와 set! 변환에서처럼 구문 객체예요. set!-transformer-procedure를 그 구조체에 적용하면 구문 객체만 받아서 속성을 통해 연관된 프로시저를 호출하는 새 함수가 만들어져요. 마지막으로 속성 값이 정수이면 대상 식별자가 구조체 인스턴스에서 추출돼요. 필드 값이 인자 하나짜리 프로시저가 아니면, 대신 항상 raise-syntax-error를 호출하는 프로시저가 사용돼요.

어떤 값이 prop:set!-transformerprop:rename-transformer 속성을 둘 다 가지면 후자가 우선해요. 구조체 타입이 prop:set!-transformerprop:procedure 속성을 가지면, 매크로 확장 목적으로는 전자가 우선해요.

procedure

(rename-transformer? v) → boolean?
  v : any/c

vmake-rename-transformer가 만든 값이거나 prop:rename-transformer 속성을 가진 구조체 타입의 인스턴스이면 #t, 그 외에는 #f를 반환해요.

예:

> (rename-transformer? (make-rename-transformer #'values))
#t
> (rename-transformer? 'not-a-rename-transformer)
#f

procedure

(make-rename-transformer id-stx) → rename-transformer?
  id-stx : syntax?

**리네임 트랜스포머(rename transformer)**를 만들어요. 트랜스포머 바인딩으로 쓰이면, 그 트랜스포머는 그 트랜스포머를 바인딩하는 식별자 대신 식별자 id-stx를 삽입하는 트랜스포머로 동작해요. 여기에는 적용 위치가 아닌 위치와 set! 표현식도 포함돼요.

이런 트랜스포머는 수동으로 작성할 수도 있지만, make-rename-transformer가 만든 것은 id가 리네임 트랜스포머에 바인딩될 때 파서와 다른 구문 형식들과 특별히 협력해요:

  • 파서는 id-stx'not-free-identifier=? 구문 속성에 대해 참 값을 갖지 않는 한, idid-stx 사이에 free-identifier=?identifier-binding 동치를 설치해요.
  • id-stx'not-free-identifier=? 구문 속성에 대해 참 값을 갖지 않고 id-stx에 바인딩이 있는 한, idprovideid 대신 id-stx가 나타내는 바인딩을 제공해요.
  • provideid를 내보내면, id-stx의 심볼 값 'nominal-id 속성을 사용해 identifier-binding이 보고하는 바인딩의 "명목 소스 식별자"를 지정해요.
  • id-stx'not-provide-all-defined 구문 속성에 대해 참 값을 가지면, id(또는 그 대상)는 all-defined-out으로 내보내지지 않아요.
  • syntax-local-value 함수는 리네임 트랜스포머 바인딩을 인식하고 그 대상들을 참조해요.

예:

> (define-syntax my-or (make-rename-transformer #'or))
> (my-or #f #t)
#t
> (free-identifier=? #'my-or #'or)
#t

base 패키지 6.3 버전에서 변경: 선택적 두 번째 인자를 제거했습니다. 7.4.0.10 버전에서 변경: 일반 매크로 확장처럼 리네임 트랜스포머 확장이 매크로-도입 스코프를 추가하도록 조정했습니다.

procedure

(rename-transformer-target transformer) → identifier?
  transformer : rename-transformer?

transformer를 만들기 위해 make-rename-transformer에 전달되었거나 transformerprop:rename-transformer 속성이 나타내는 식별자를 반환해요.

예:

> (rename-transformer-target (make-rename-transformer #'or))
#<syntax:eval:8:0 or>

value

prop:rename-transformer : struct-type-property?

make-rename-transformer가 만든 것 같은 리네임 트랜스포머 역할을 하는 구조체 타입을 식별하는 구조체 타입 속성이에요.

속성 값은 정확한 정수, 식별자 구문 객체, 또는 인자 하나를 받는 프로시저여야 해요. 전자의 경우 정수는 구조체 안에서 식별자를 담아야 할 필드를 지정하며, 정수는 0(포함)과 구조체 타입의 비자동 필드 수(배타, 슈퍼타입 필드는 세지 않음) 사이여야 하고, 지정된 필드는 불변으로도 지정되어야 해요.

속성 값이 식별자이면 그 식별자가 make-rename-transformer의 첫 인자처럼 리네임의 대상 역할을 해요. 속성 값이 정수이면 대상 식별자가 구조체 인스턴스에서 추출돼요. 필드 값이 식별자가 아니면, 대신 빈 문맥을 가진 식별자 ?가 사용돼요.

속성 값이 인자 하나를 받는 프로시저이면, 리네임 트랜스포머가 대상 식별자로 쓸 식별자를 얻기 위해 그 프로시저를 호출해요. 반환된 식별자는 아마도 'not-free-identifier=? 구문 속성을 가져야 해요. 프로시저가 식별자가 아닌 어떤 값을 반환하면 exn:fail:contract 예외가 발생해요.

예:

; Example of a procedure argument for prop:rename-transformer
> (define-syntax slv-1 'first-transformer-binding)
> (define-syntax slv-2 'second-transformer-binding)

> (begin-for-syntax
    (struct slv-cooperator (redirect-to-first?)
      #:property prop:rename-transformer
      (λ (inst)
        (if (slv-cooperator-redirect-to-first? inst)
            #'slv-1
            #'slv-2))))

> (define-syntax (slv-lookup stx)
    (syntax-case stx ()
      [(_ id)
       #`'#,(syntax-local-value #'id)]))
> (define-syntax slv-inst-1 (slv-cooperator #t))
> (define-syntax slv-inst-2 (slv-cooperator #f))
> (slv-lookup slv-inst-1)
'first-transformer-binding
> (slv-lookup slv-inst-2)
'second-transformer-binding

base 패키지 6.3 버전에서 변경: 이 속성이 이제 인자 하나짜리 프로시저를 받습니다.

procedure

(local-expand  stx
               context-v
               stop-ids
               [ intdef-ctx])   →   syntax?
  stx : any/c
  context-v : (or/c 'expression 'top-level 'module 'module-begin list?)
  stop-ids : (or/c (listof identifier?) empty #f)
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f

현재 확장 중인 표현식의 어휘 문맥에서 stx를 확장해요. context-v 인자는 즉각적인 확장에 대한 syntax-local-context의 결과로 사용돼요. 목록은 내부-정의 문맥을 나타내며, 목록 형태에 대한 추가 정보는 아래에 있어요. stx가 아직 구문 객체가 아니면 확장 전에 (datum->syntax #f stx)로 강제 변환돼요.

stop-ids 인자는 local-expandstx를 얼마나 확장하는지 통제해요:

  • stop-ids가 빈 목록이면, stx가 재귀적으로 확장돼요(즉 확장이 하위 표현식으로 진행). 결과는 완전히 확장된 형식임이 보장돼요. 이는 Fully Expanded Programs에 나열된 바인딩과, 어떤 표현식 위치에서든 #%expression을 포함할 수 있어요.
  • stop-idsmodule*만 담은 목록이면, module*로 정의된 서브모듈로는 확장이 재귀하지 않는다는 것(결과에서 확장되지 않은 채 남겨짐)만 빼면 stop-ids가 빈 목록일 때처럼 확장이 진행돼요.
  • stop-ids가 그 밖의 어떤 목록이면, begin, quote, set!, #%plain-lambda, case-lambda, let-values, letrec-values, if, begin0, with-continuation-mark, letrec-syntaxes+values, #%plain-app, #%expression, #%top, #%variable-referencestop-ids에 암시적으로 추가돼요. 확장은 재귀적으로 진행되며, 확장기가 stop-ids의 어떤 형식도 만나면 멈추고, 결과는 부분적으로 확장된 형식이에요.

확장기가 Expansion Steps에서 설명한 대로 #%app, #%datum, #%top 식별자를 암시적으로 도입하려 할 때, 도입될 것과 같은 바인딩을 가진 식별자가 stop-ids에 있는지 확인해요. 있으면 그 식별자는 도입되지 않아요. 확장 결과는 각각의 명시적 형식으로 감싸지지 않은 그대로의 적용, 리터럴 데이터 표현식, 또는 unbound 식별자예요.

#%plain-module-beginstop-ids에 없으면, #%plain-module-begin 트랜스포머는 식별자가 stop-ids에 있는지와 무관하게 하위 형식(예: define-values)을 감지하고 확장해요.

확장은 지역 변수 참조의 스코프를 바인딩 식별자와 일치하도록 대체하지 않아요.

  • stop-ids가 목록이 아니라 #f이면, stx의 가장 바깥 형식이 매크로인 동안에만 stx가 확장돼요(즉 확장이 하위 표현식으로 진행되지 않고, 지역 변수 참조의 스코프를 바인딩 식별자와 일치하도록 대체하지 않음). #%app, #%datum, #%top 식별자는 결코 도입되지 않아요.

stop-ids와 무관하게, local-expand가 지역 바인딩이 있지만 현재 확장 문맥에는 바인딩이 없는 식별자를 만나면, 그 변수는 ("out of context" 구문 오류를 촉발하는 대신) 그대로 남겨져요.

context-v'module-begin이고 확장 결과가 #%plain-module-begin 형식이면, 각 둘러싸인 module 형식(단 module* 형식은 아님)에 모듈 확장에서처럼 'submodule 구문 속성이 추가돼요.

intdef-ctx 인자가 내부-정의 문맥이면, local-expand 호출의 동적 범위 동안 그 바인딩들과 모든 부모 내부-정의 문맥의 바인딩들이 지역 바인딩 문맥에 추가돼요. 추가로, 내부-정의 문맥을 만들 때 syntax-local-make-definition-contextadd-scope? 인자에 #f가 제공되지 않았다면, 그 내부-정의 문맥의 안쪽-가장자리 스코프(부모 내부-정의 문맥의 스코프는 아님)가 확장 전의 stx와 확장 결과의 어휘 정보 양쪽에 추가돼요(확장이 바인딩이나 내부-정의 바인딩에 대한 참조를 도입할 수 있기 때문).

역호환성을 위해, intdef-ctx가 목록이면 제공된 모든 내부-정의 문맥과 그 부모들의 모든 바인딩이 지역 바인딩 문맥에 추가되고, add-scope?#f가 아닌 각 문맥의 안쪽-가장자리 스코프가 같은 방식으로 추가돼요.

확장은 정의 바인딩에서 제거하기 위해 사용-지점 스코프를 기록해요. intdef-ctx 인자가 내부-정의 문맥이면 사용-지점 스코프가 그 문맥으로 기록돼요. intdef-ctx#f이거나(역호환성으로) 목록이면, 사용-지점 스코프는 현재 확장 문맥으로 기록돼요.

특정 내부-정의 문맥에 대해 고유한 값을 만들어 context-v용 목록에 넣어요. define 형식의 자유로운 확장을 허용하려면, 생성된 값은 prop:liberal-define-context에 대해 참 값을 가진 구조체의 인스턴스여야 해요. 내부-정의 문맥이 자기 완결적이려면 context-v용 목록이 생성된 값만 담아야 해요. 내부-정의 문맥이 바로 둘러싼 문맥으로 이어 붙여지도록 의도되었으면, syntax-local-context가 목록을 만들 때 생성된 값을 그 목록에 cons해요.

표현식이 내부-정의 문맥 intdef-ctxlocal-expand를 통해 확장되고, 확장된 표현식이 전체 형식 new-stx에 통합되면, 보통 internal-definition-context-trackintdef-ctxnew-stx에 적용해 외부 도구에 확장 이력을 제공해야 해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

예:

> (define-syntax-rule (do-print x ...)
    (printf x ...))

> (define-syntax-rule (hello x)
    (do-print "hello ~a" x))

> (define-syntax (show stx)
    (syntax-case stx ()
      [(_ x)
       (let ([partly (local-expand #'(hello x)
                                   'expression
                                   (list #'do-print))]
             [fully (local-expand #'(hello x)
                                  'expression
                                  #f)])
         (printf "partly expanded: ~s\n" (syntax->datum partly))
         (printf "fully expanded: ~s\n" (syntax->datum fully))
         fully)]))
> (show 1)

partly expanded: (do-print "hello ~a" 1)

fully expanded: (printf "hello ~a" 1)

hello 1

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 6.0.1.3 버전에서 변경: #%top이 명시적 래퍼로 결코 도입되지 않도록 처리를 변경했습니다. 6.0.90.27 버전에서 변경: intdef-ctx 인자에 대한 계약을 느슨하게 해 빈 목록을 허용했습니다. 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

procedure

(syntax-local-expand-expression  stx
                                 [ opaque-only?])
  → (if opaque-only? #f syntax?)  syntax?
  stx : any/c
  opaque-only? : any/c = #f

'expression과 빈 멈춤 목록을 준 local-expand와 같지만, 결과가 두 개예요. 하나는 완전히 확장된 표현식용 구문 객체, 다른 하나는 내용이 불투명한 구문 객체예요.

후자는 전자 대신(어쩌면 매크로 트랜스포머가 만든 더 큰 표현식 안에서) 사용될 수 있어요. 매크로 확장기가 불투명 객체를 만나면, 재확장 없이 완전히 확장된 표현식을 대체해요. 확장 문맥에 원래 확장에 없던 스코프가 포함되어 있으면 exn:fail:syntax 예외가 발생하는데, 이 경우 재확장이 다른 결과를 만들 수 있어요. syntax-local-expand-expression과 불투명 객체를 일관되게 사용하면, 지역 확장이 중첩될 때 이차 확장 시간을 피할 수 있어요.

opaque-only?가 참이면 첫 결과는 확장된 표현식 대신 #f예요. 두 번째 불투명 결과만 얻는 것은 일부 확장 문맥에서 더 효율적일 수 있어요.

local-expand와 달리, syntax-local-expand-expression은 보통 #%expression 형식을 포함하지 않는 확장된 표현식을 만들어요. 그러나 syntax-local-expand-expression이 둘러싼 local-expand 호출이 촉발한 확장 안에서 사용되면, syntax-local-expand-expression의 결과가 #%expression 형식을 포함할 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 6.90.0.13 버전에서 변경: opaque-only? 인자를 추가했습니다. 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

procedure

(local-transformer-expand  stx
                           context-v
                           stop-ids
                           [ intdef-ctx])   →   syntax?
  stx : any/c
  context-v : (or/c 'expression 'top-level list?)
  stop-ids : (or/c (listof identifier?) #f)
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f

local-expand와 같지만, stx가 실행-시간 표현식 대신 트랜스포머 표현식으로 확장돼요.

끌어올려진(lifted) 표현식들—stx 확장 중 syntax-local-lift-expression 호출로 생긴 것—이 결과에 포착돼요. context-v'top-level이면 끌어올림이 begin 형식으로 포착되고, 그 외에는 끌어올림이 let-values 형식으로 포착돼요. 확장 중 끌어올려진 표현식이 없으면 begin이나 let-values 래퍼는 추가되지 않아요.

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 6.5.0.3 버전에서 변경: 'top-level 문맥에서의 끌어올림을 허용하고 포착했습니다. 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

procedure

(local-expand/capture-lifts  stx
                             context-v
                             stop-ids
                             [ intdef-ctx
                               lift-ctx])   →   syntax?
  stx : any/c
  context-v : (or/c 'expression 'top-level 'module 'module-begin list?)
  stop-ids : (or/c (listof identifier?) #f)
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f
  lift-ctx : any/c = (gensym 'lifts)

local-expand와 같지만, 결과는 begin 표현식을 나타내는 구문 객체예요. 끌어올려진 표현식들—stx 확장 중 syntax-local-lift-expression 호출로 생긴 것—이 그 식별자들과 함께 define-values 형식으로 나타나고, stx의 확장이 begin의 마지막 표현식이에요. lift-ctx 값은 지역 확장 중 syntax-local-lift-context가 보고해요. 끌어올려진 표현식은 확장되지 않고, 대신 begin 형식에 제공된 그대로 남겨져요.

context-v'top-level이나 'module이면 syntax-local-lift-module로 추가된 module 형식이 결과에 나타날 수 있어요. context-v'module이면 module* 형식도 나타날 수 있어요.

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

procedure

(local-transformer-expand/capture-lifts  stx
                                         context-v
                                         stop-ids
                                         [ intdef-ctx
                                           lift-ctx])   →   syntax?
  stx : any/c
  context-v : (or/c 'expression 'top-level list?)
  stop-ids : (or/c (listof identifier?) #f)
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f
  lift-ctx : any/c = (gensym 'lifts)

local-expand/capture-lifts와 같지만, stx가 실행-시간 표현식 대신 트랜스포머 표현식으로 확장돼요. 끌어올려진 표현식들은 (트랜스포머 환경에서) define-values 형식으로 보고돼요.

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

문맥-민감 트랜스포머 도구 (Context-Sensitive Transformer Tools)

procedure

(syntax-local-apply-transformer  transformer
                                 binding-id/insp
                                 context-v
                                 intdef-ctx
                                 v ...)   →   any
  transformer : procedure?
  binding-id/insp : (or/c #f identifier? inspector?
                         (list identifier? inspector?))
  context-v : (or/c 'expression 'top-level 'module 'module-begin list?)
  intdef-ctx : (or/c internal-definition-context? #f)
  v : any/c

프로시저 트랜스포머를 새 확장 문맥과 지역 바인딩 문맥에서 v들에 적용해요. 구문 트랜스포머 적용과 같은 방식으로 인자와 반환 값에 매크로-도입 스코프와 사용-지점 스코프를 추가하고 뒤집어요. 인자와 반환값은 어떤 값이든 될 수 있으며, 스코프는 구문 객체인 것에 대해서만 조작돼요.

context-v 인자는 local-expand에서처럼이고, intdef-ctx는 내부-정의 문맥 값이거나 #f예요.

binding-id/insp 인자는 최대 두 개의 추가 인자를 부호화해요: 식별자로서 biding-id와 인스펙터로서 expander-insp. binding-id 부분은 제공되면 트랜스포머와 연관된 바인딩을 지정하며, 확장기가 이를 사용해 사용-지점 스코프를 추가할지, 확장 동안 어떤 코드 인스펙터를 쓸지 결정해요. expander-insp 부분은 확장기 자신을 위한 코드 인스펙터를 지정하며, 기본값은 현재 진행 중인 트랜스포머의 바인딩과 연관된 코드 인스펙터예요. 관련 인스펙터는, 인스펙터들이 비교 가능하면 binding-idexpander-insp가 암시하는 것의 하위(inspector-superior?의 의미에서)이며, 그렇지 않으면 인스펙터가 없어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 8.2.0.7 버전에서 추가. 8.18.0.15 버전에서 변경: binding-id/inspexpander-insp 구성 요소를 허용하도록 변경했습니다.

procedure

(internal-definition-context? v) → boolean?
  v : any/c

v가 내부-정의 문맥이면 #t, 그 외에는 #f를 반환해요.

procedure

(syntax-local-make-definition-context  [ parent-ctx
                                         add-scope?])
  → internal-definition-context?
  parent-ctx : (or/c internal-definition-context? #f) = #f
  add-scope? : any/c = #t

local-expand와 다른 함수들과 함께 쓸 불투명한 내부-정의 문맥(internal-definition context) 값을 만들어요. 트랜스포머는 확장할 내부 정의 각 집합마다 문맥 하나를 만들어야 해요.

어휘 문맥에 그 정의들을 포함해야 하는 형식을 확장하기 전에, 트랜스포머는 internal-definition-context-add-scopes를 사용해 문맥의 스코프를 구문에 적용해야 해요. 그 형식을 확장하는 local-expand 같은 절차 호출은 내부-정의 문맥 값을 인자로 제공해야 해요.

내부 define-values 또는 define-syntaxes 형식을 발견한 뒤에는 syntax-local-bind-syntaxes를 사용해 문맥에 바인딩을 추가해요.

내부-정의 문맥은 내부적으로 문맥을 나타내기 위해 바깥-가장자리 스코프와 안쪽-가장자리 스코프를 만든다. 안쪽-가장자리 스코프는 문맥 안에서 확장되는 모든 형식이나 문맥 안에서의 (부분) 확장 결과로 나타나는 모든 형식에 추가돼요. 역호환성을 위해 add-scope?#f를 제공하면 이 동작을 비활성화해요.

parent-ctx#f가 아니면, parent-ctx가 새 내부-정의 문맥의 부모 내부-정의 문맥이 돼요. 새 문맥의 바인딩이 지역 바인딩 문맥에 추가될 때마다(예: local-expand, syntax-local-bind-syntaxes, syntax-local-value에 문맥을 제공함으로써), parent-ctx의 바인딩도 함께 추가돼요. parent-ctx도 부모 내부-정의 문맥으로 만들어졌다면 그 부모의 바인딩도 추가되고, 재귀적으로 계속돼요. 부모 문맥의 스코프는 암시적으로 추가되지 않고 바인딩만 추가된다는 점에 주의하세요. 자식 문맥의 안쪽-가장자리 스코프가 암시적으로 추가되더라도 그렇습니다. 부모 정의 문맥의 스코프를 추가해야 한다면 부모 문맥을 명시적으로 제공해야 해요.

추가로, 만든 정의 문맥이 둘러싼 정의 문맥으로 이어 붙여지도록 의도되었다면, 문맥에서 확장되는 매크로에 필요한 사용-지점 스코프가 추가되도록 parent-ctx 인자에 둘러싼 문맥을 항상 제공해야 해요. 그렇지 않으면 중첩 정의의 확장이 둘러싼 문맥의 정의 확장과 일관되지 않을 수 있어요.

내부-정의 문맥은 또한 정의 문맥 안의 확장 중 만들어진 사용-지점 스코프를 추적해, syntax-local-identifier-as-bindinginternal-definition-context-splice-binding-identifier에서 문맥에 만든 바인딩에서 제거할 수 있게 해요.

새 정의 문맥과 연관된 스코프는, 구문 트랜스포머 적용의 동적 범위 동안이나 확장 중인 모듈 안의 begin-for-syntax 형식(잠재적으로 중첩)에서 만들어질 때만 quote-syntax 형식에서 가지치기돼요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 6.3 버전에서 변경: add-scope? 인자를 추가하고, internal-definition-context-seal 호출이 더 이상 필요 없게 만들었습니다. 8.2.0.7 버전에서 변경: 바깥-가장자리 스코프와 사용-지점 스코프 추적 동작을 추가했습니다.

procedure

(syntax-local-make-definition-context-introducer [name])
  → ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?)
  name : (and/c symbol? (not/c 'macro)) = 'intdef

make-syntax-introducer와 같지만, 캡슐화된 스코프가 quote-syntax 형식에서 가지치기돼요. 이는 새 정의 문맥과 연관된 스코프와 매우 비슷합니다(syntax-local-make-definition-context 참조). name 인자는 기호 이름으로 사용되며 디버깅 보조 역할을 해요.

보통은 internal-definition-context-add-scopesinternal-definition-context-splice-binding-identifier가 선호되지만, quote-syntax 형식에서 가지치기되어야 할 단일 스코프를 원한다고 확신할 때 이 함수가 유용할 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 8.12.0.8 버전에서 추가.

procedure

(internal-definition-context-add-scopes  intdef-ctx
                                         stx)   →   syntax?
  intdef-ctx : internal-definition-context?
  stx : syntax?

intdef-ctx의 바깥-가장자리 스코프와 안쪽-가장자리 스코프를 stx에 추가해요.

이 함수를 사용해 확장 전에 정의 문맥 안에서 기원한 구문에 정의 문맥 스코프를 적용해요.

base 패키지 8.2.0.7 버전에서 추가.

procedure

(internal-definition-context-splice-binding-identifier  intdef-ctx
                                                        id)
  → syntax?
  intdef-ctx : internal-definition-context?
  id : identifier?

intdef-ctx와 연관된 스코프를 id에서 제거해요: 바깥-가장자리 스코프, 안쪽-가장자리 스코프, 그리고 정의 문맥 안의 확장이 만든 사용-지점 스코프.

intdef-ctx 안에서 기원한 바인딩을 둘러싼 문맥으로 이어 붙일 때 사용해요.

base 패키지 8.2.0.7 버전에서 추가.

procedure

(syntax-local-bind-syntaxes  id-list
                             expr
                             intdef-ctx
                             [ extra-intdef-ctxs])
  → (listof identifier?)
  id-list : (listof identifier?)
  expr : (or/c syntax? #f)
  intdef-ctx : internal-definition-context?
  extra-intdef-ctxs : (or/c internal-definition-context?
                           (listof internal-definition-context?)) = '()

intdef-ctx가 나타내는 내부-정의 문맥 안에서 id-list의 각 식별자를 바인딩해요. 여기서 intdef-ctxsyntax-local-make-definition-context의 결과예요. 새 바인딩과 일치하는 어휘 정보를 가진 식별자들을 반환해요.

역호환성을 위해, extra-intdef-ctxs의 각 요소의 어휘 정보도 바인딩 전에 id-list의 각 식별자에 추가돼요.

식별자가 define-values 바인딩에 대응하면 expr#f를 제공하고, define-syntaxes 바인딩에 대응하면 컴파일-시간 표현식을 제공해요. 후자의 경우 표현식이 만드는 값의 수가 식별자 수와 일치해야 하며, 그렇지 않으면 exn:fail:contract:arity 예외가 발생해요.

expr#f가 아니면 표현식 문맥에서 확장되고 현재 트랜스포머 환경에서 평가돼요. 이 경우 intdef-ctxextra-intdef-ctxs 양쪽의 바인딩과 어휘 정보가 local-expand의 네 번째 인자와 같은 방식으로 expr의 어휘 정보를 풍부하게 하고 지역 바인딩 문맥을 확장하는 데 사용돼요. expr#f이면 extra-intdef-ctxs에 제공된 값은 무시돼요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 6.90.0.27 버전에서 변경: extra-intdef-ctxs 인자를 추가했습니다. 8.2.0.7 버전에서 변경: 반환 값을 #<void>에서 바인딩된 식별자 목록으로 변경했습니다.

procedure

(internal-definition-context-binding-identifiers intdef-ctx)
  → (listof identifier?)
  intdef-ctx : internal-definition-context?

syntax-local-bind-syntaxes를 통해 intdef-ctx에 등록된 모든 바인딩 식별자 목록을 반환해요. 반환된 목록의 각 식별자는 내부-정의 문맥의 스코프를 포함해요.

base 패키지 6.3.0.4 버전에서 추가.

procedure

(internal-definition-context-introduce  intdef-ctx
                                        stx
                                        [ mode])   →   syntax?
  intdef-ctx : internal-definition-context?
  stx : syntax?
  mode : (or/c 'flip 'add 'remove) = 'flip

mode에 따라 stx의 모든 부분에 대해 intdef-ctx의 스코프를 뒤집거나, 추가하거나, 제거해요.

이 함수는 역호환성을 위해 제공돼요. internal-definition-context-add-scopesinternal-definition-context-splice-binding-identifier가 선호됩니다. quote-syntax 형식에서 가지치기되어야 할 단일 스코프를 캡슐화하는 방법은 syntax-local-make-definition-context-introducer도 보세요.

base 패키지 6.3 버전에서 추가.

procedure

(internal-definition-context-seal intdef-ctx) → void?
  intdef-ctx : internal-definition-context?

역호환성을 위해서만 제공되며, 효과가 없어요.

procedure

(identifier-remove-from-definition-context  id-stx
                                            intdef-ctx)
  → identifier?
  id-stx : identifier?
  intdef-ctx : (or/c internal-definition-context?
                    (listof internal-definition-context?))

id-stx에서 intdef-ctx의 모든 스코프(또는 목록 intdef-ctx의 각 요소의 스코프)를 제거해요.

identifier-remove-from-definition-context 함수는 역호환성을 위해 제공돼요. internal-definition-context-splice-binding-identifier 함수가 선호됩니다.

base 패키지 6.3 버전에서 변경: 연산을 스코프 제거로 단순화했습니다.

value

prop:expansion-contexts : struct-type-property?

매크로 트랜스포머와 리네임 트랜스포머의 사용을 제한하는 구조체 타입 속성이에요. 속성의 값은 심볼 목록이어야 하며, 허용되는 심볼은 'expression, 'top-level, 'module, 'module-begin, 'definition-context예요. 각 심볼은 local-expand에서처럼 또는 syntax-local-context가 보고하듯이 확장 문맥에 대응하지만, (definition-context는 목록 대신) 내부-정의 문맥을 나타내는 데 'definition-context가 사용돼요.

어떤 식별자가 그 식별자의 특정 사용에 대한 심볼을 목록에 포함하지 않는 트랜스포머에 바인딩되어 있으면, 그 사용은 다음과 같이 조정돼요:

  • 'module-begin 문맥이면, 그 사용이 begin 형식으로 감싸져요.
  • 'module, 'top-level, 'internal-definition 또는 문맥이면, 목록에 'expression이 있으면 그 사용이 #%expression 형식으로 감싸져요.
  • 그 외에는 구문 오류가 보고돼요.

prop:expansion-contexts 속성은 prop:rename-transformer와 함께 쓸 때 가장 유용해요. 일반 트랜스포머 프로시저는 syntax-local-context를 사용할 수 있기 때문입니다. 게다가 prop:expansion-contexts 속성은 리네임 트랜스포머의 식별자가 'not-free-identifier=? 속성을 가질 때 가장 의미가 있어요. 그렇지 않으면 그 바인딩의 정의가 바인딩 별칭을 만들어 prop:expansion-contexts 속성을 실질적으로 우회하게 되기 때문입니다.

base 패키지 6.3 버전에서 추가.

값·위상·문맥 질의 (Value, Phase, and Context Queries)

procedure

(syntax-local-value  id-stx
                     [ failure-thunk
                       intdef-ctx])   →   any
  id-stx : identifier?
  failure-thunk : (or/c (-> any) #f) = #f
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f

현재 확장의 문맥에서 식별자 id-stx의 트랜스포머 바인딩 값은 반환해요. intdef-ctx#f가 아니면 제공된 모든 정의 문맥의 바인딩도 고려돼요. local-expand의 네 번째 인자와 달리, 제공된 정의 문맥과 연관된 스코프는 id-stx의 어휘 정보를 풍부하게 하는 데 사용되지 않아요.

id-stxmake-rename-transformer로 만든 리네임 트랜스포머에 바인딩되어 있으면, syntax-local-value는 리네임의 대상으로 자신을 재귀 호출하고 그 결과를 반환해요. 리네임 트랜스포머 자체는 아닙니다.

id-stx가 그 환경에서 트랜스포머 바인딩(define-syntax, let-syntax 등을 통한)이 없으면, failure-thunk#f가 아니면 그것을 적용해 결과를 얻어요. failure-thunk가 거짓이면 exn:fail:contract 예외가 발생해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

예:

> (define-syntax swiss-cheeses? #t)

> (define-syntax (transformer stx)
    (if (syntax-local-value #'swiss-cheeses?)
        #''(gruyère emmental raclette)
        #''(roquefort camembert boursin)))
> (transformer)
'(gruyère emmental raclette)

예:

> (define-syntax (transformer-2 stx)
    (syntax-local-value #'something-else (λ () (error "no binding"))))
> (transformer-2)
no binding

예:

> (define-syntax nachos #'(printf "nachos~n"))
> (define-syntax chips (make-rename-transformer #'nachos))

> (define-syntax (transformer-3 stx)
    (syntax-local-value #'chips))
> (transformer-3)
nachos

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 6.90.0.27 버전에서 변경: intdef-ctx가 단일 내부-정의 문맥이나 #f에 더해 내부-정의 문맥 목록을 받도록 변경했습니다. 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

procedure

(syntax-local-value/immediate  id-stx
                               [ failure-thunk
                                 intdef-ctx])   →   any
  id-stx : syntax?
  failure-thunk : (or/c (-> any) #f) = #f
  intdef-ctx : (or/c internal-definition-context?
                    #f
                    (listof internal-definition-context?))   =   #f

syntax-local-value와 같지만, 결과가 보통 두 값이에요. id-stx가 리네임 트랜스포머에 바인딩되어 있으면, 결과는 리네임 트랜스포머와 그 안의 식별자예요. 유의: 리네임 트랜스포머에 바인딩된 id에 대한 provideid 대신 리네임의 대상을 내보낼 수 있어요. 자세한 내용은 make-rename-transformer를 보세요. id-stx가 리네임 트랜스포머에 바인딩되어 있지 않으면, 결과는 syntax-local-value가 만들었을 값과 #f예요.

id-stx에 트랜스포머 바인딩이 없으면 failure-thunk가 호출되고(어떤 수의 값도 반환할 수 있음), failure-thunk#f이면 예외가 발생해요.

예:

> (define-syntax agent-007 (make-rename-transformer #'james-bond))

> (define-syntax (show-secret-identity stx)
    (syntax-parse stx
      [(_ name:id)
       (define-values [_ orig-name] (syntax-local-value/immediate #'name))
       #`'(name #,orig-name)]))
> (show-secret-identity agent-007)
'(agent-007 james-bond)

이 절차의 바인딩은 protect-out의 의미에서 protected로 제공돼요.

base 패키지 8.2.0.4 버전에서 변경: 바인딩을 protected로 변경했습니다.

끌어올림 (Lifting)

procedure

(syntax-local-lift-expression stx) → identifier?
  stx : syntax?

새 식별자를 반환하고, 모듈, letrec-syntaxes+values, define-syntaxes, begin-for-syntax, 최상위 확장기들과 협력해 생성된 식별자를 표현식 stx에 바인딩해요.

모듈 안의 실행-시간 표현식은, 끌어올림을 요청한 표현식 바로 앞에서 모듈의 최상위로 끌어올려져요. 비슷하게 모듈 밖의 실행-시간 표현식은 최상위 정의로 끌어올려져요. letrec-syntaxes+valuesdefine-syntaxes 바인딩의 컴파일-시간 표현식은 바인딩의 대응하는 오른쪽 주위에 있는 let 래퍼로 끌어올려져요. begin-for-syntax 안의 컴파일-시간 표현식은 begin-for-syntax 안에서 요청 표현식 바로 앞의 define 선언으로 끌어올려져요.

다른 구문 형식은 local-expand/capture-liftslocal-transformer-expand/capture-lifts를 사용해 끌어올림을 포착할 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 추가로 이 절차는 syntax-transforming-with-lifts?가 나타내듯이 끌어올림 대상이 이용 가능할 때만 호출될 수 있어요.

procedure

(syntax-local-lift-values-expression n stx)
  → (listof identifier?)
  n : exact-nonnegative-integer?
  stx : syntax?

syntax-local-lift-expression과 같지만, 결과를 n개의 식별자에 바인딩하고 그 n개 식별자 목록을 반환해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-lift-context) → any/c

syntax-local-lift-expression으로 끌어올려진 표현식의 대상을 나타내는 값을 반환해요. 즉, 이 절차가 같은 값을(eq?로 결정) 반환하는 서로 다른 트랜스포머 호출에 대해, 두 트랜스포머의 끌어올려진 표현식이 같은 곳으로 옮겨져요. 따라서 결과는 불필요한 끌어올림을 피하기 위해 끌어올림 정보를 캐시하는 데 유용해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-lift-module stx) → void?
  stx : syntax?

모듈 형식이나 최상위 확장과 협력해 stx를 둘러싼 모듈이나 최상위에 모듈 선언으로 추가해요. stx 형식은 module이나 module*로 시작해야 하며, 후자는 모듈의 확장 안에서만 허용돼요.

모듈은 syntax-local-lift-module이 반환할 때 즉시 선언되지 않아요. 대신 모듈 선언은 확장이 둘러싼 모듈 본문이나 최상위 수열로 돌아올 때 처리를 위해 기록돼요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 변형되는 현재 표현식이 모듈 형식 안이나 최상위 확장 안에 없으면 exn:fail:contract 예외가 발생해요. stx 형식이 module이나 module*로 시작하지 않거나, 최상위 문맥에서 module*로 시작하면 exn:fail:contract 예외가 발생해요.

base 패키지 6.3 버전에서 추가.

procedure

(syntax-local-lift-module-end-declaration stx) → void?
  stx : syntax?

모듈 형식과 협력해 stx를 현재 확장 중인 모듈 끝의 최상위 선언으로 삽입해요. 변형되는 현재 표현식이 위상 레벨 0이고 모듈 최상위에 없으면, stx는 결국 표현식 문맥에서 확장돼요. 변형되는 현재 표현식이 더 높은 위상 레벨(즉 모듈 최상위 안의 어떤 수의 begin-for-syntax 안에 중첩)이면, 끌어올려진 선언은 단지 둘러싼 begin-for-syntax의 끝이 아니라 (적절한 수의 begin-for-syntax 아래에서) 모듈의 맨 끝에 놓여져요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 변형되는 현재 표현식이 모듈 형식 안에 없으면(syntax-transforming-module-expression? 참조) exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-lift-require  raw-require-spec
                            stx
                            [ new-scope?])   →   syntax?
  raw-require-spec : any/c
  stx : syntax?
  new-scope? : any/c = #t

raw-require-spec(구문 객체 또는 datum으로)에 대응하는 #%require 형식을 최상위, 또는 현재 확장 중인 모듈의 최상위, 또는 둘러싼 begin-for-syntax끌어올려요.

결과 구문 객체는 new-scope?가 참이면 새 스코프가 추가된다는 것만 빼면 stx와 같아요. 끌어올려진 #%require 형식에도 같은 스코프가 추가되어, 그 #%require 형식이 결과 구문 객체에서 임포트된 식별자의 사용을 바인딩할 수 있어요(stx의 어휘 정보가 #%require가 끌어올려진 바인딩 환경을 포함한다고 가정). new-scope?#f이면 결과는 정확히 stx이고 끌어올려진 #%require 형식에는 스코프가 추가되지 않아요. 그 경우 끌어올려진 require가 모듈 안에서 이미 확장된 식별자의 의미를 바꾸지 않도록 주의해야 해요. 그렇지 않으면 둘러싼 모듈의 재확장이 확장된 모듈과 같은 결과를 만들지 않습니다.

raw-require-spec가 트랜스포머의 입력의 일부이면, 보통 syntax-local-lift-require에 넘기기 전에 syntax-local-introduce를 적용해야 해요. 그렇지 않으면 매크로 확장기가 추가한 마크가 새 임포트에 대한 접근을 막을 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 6.90.0.27 버전에서 변경: 입력에 추가되는 스코프를 매크로-도입 스코프에서, 결과 구문이 syntax-original?이 보고하는 origin 것으로 간주되는지 여부에 영향을 주지 않는 스코프로 변경했습니다. 8.6.0.4 버전에서 변경: new-scope? 선택 인자를 추가했습니다.

procedure

(syntax-local-lift-provide raw-provide-spec-stx) → void?
  raw-provide-spec-stx : syntax?

raw-provide-spec-stx에 대응하는 #%provide 형식을 현재 확장 중인 모듈의 맨 위나 둘러싼 begin-for-syntax으로 끌어올려요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 변형되는 현재 표현식이 모듈 형식 안에 없으면(syntax-transforming-module-expression? 참조) exn:fail:contract 예외가 발생해요.

기타 문맥·이력 질의 (Other Context and History Queries)

procedure

(syntax-local-name) → any/c

변형되는 표현식 위치에 대해 추론된 이름을 반환하거나, 그런 이름을 이용할 수 없으면 #f를 반환해요. 이름은 보통 심볼이나 식별자예요. Inferred Value Names도 보세요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-context)
  → (or/c 'expression 'top-level 'module 'module-begin list?)

구문 트랜스포머 호출을 촉발한 확장의 문맥을 나타내는 값을 반환해요. 문맥에 대한 자세한 정보는 Expansion Context를 보세요.

심볼 결과는 그 표현식이 표현식 문맥, 최상위 문맥, 모듈 문맥, module-begin 문맥에서 확장되고 있음을 나타내요.

목록 결과는 내부-정의 문맥에서의 확장을 나타내요. 목록의 첫 요소의 동일성(즉 eq?성)이 내부-정의 문맥의 동일성을 반영해요. 특히 두 트랜스포머 확장은 같은 내부-정의 문맥을 위해 호출될 때에만 같은 첫 값을 받아요. 목록의 이후 값은 계속 확장 중이고 중첩된 내부-정의 문맥의 확장을 요구한 내부-정의 문맥을 비슷하게 식별해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-phase-level) → exact-integer?

확장기가 구문 트랜스포머를 적용하는 동적 범위 동안 결과는 확장되는 형식의 위상 레벨이에요. 그 외에는 결과가 0이에요.

예:

; a macro bound at phase 0
> (define-syntax (print-phase-level stx)
    (printf "phase level: ~a~n" (syntax-local-phase-level))
    #'(void))
> (require (for-meta 2 racket/base))

> (begin-for-syntax
    ; a macro bound at phase 1
    (define-syntax (print-phase-level stx)
      (printf "phase level: ~a~n" (syntax-local-phase-level))
      #'(void)))
> (print-phase-level)
phase level: 0
> (begin-for-syntax (print-phase-level))
phase level: 1

procedure

(syntax-local-module-exports mod-path)
  → (listof (cons/c phase+space? (listof symbol?)))
  mod-path : (or/c module-path?
                   (syntax/c module-path?))

위상 레벨과 바인딩 공간 조합에서 심볼 목록으로의 연관 목록을 반환해요. 심볼들은 대응하는 위상 레벨에서 mod-path가 제공한 바인딩들의 이름이에요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 8.2.0.3 버전에서 변경: 결과를 위상–공간 조합으로 일반화했습니다.

procedure

(syntax-local-submodules) → (listof symbol?)

현재 확장 문맥에서 module(module*가 아닌)로 선언된 서브모듈 이름 목록을 반환해요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

procedure

(syntax-local-module-interned-scope-symbols)
  → (listof symbol?)

현재 확장 문맥의 모듈이나 최상위 네임스페이스 안의 바인딩을 위해 지금까지 사용된 바인딩 공간에 대응하는 구별된 interned 심볼 목록을 반환해요. 결과는 현재 모듈이나 네임스페이스에서 사용되지 않은 추가 심볼을 포함할 수 있다는 점에서 보수적이에요.

현재 구현은 도달 가능한 interned 스코프에 대한 모든 심볼을 반환하지만, 이 동작은 미래에 덜 보수적인 심볼 목록을 반환하도록 바뀔 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 8.2.0.7 버전에서 추가.

procedure

(syntax-local-get-shadower  id-stx
                            [ only-generated?])   →   identifier?
  id-stx : identifier?
  only-generated? : any/c = #f

id-stx가 현재 확장 문맥의 바인딩을 참조하거나, 더 중첩된 문맥에서 (syntax-local-get-shadower id-stx)로 얻은 어떤 식별자도 바인딩할 수 있도록 id-stx에 스코프를 추가해요. only-generated?가 참이면, 둘러싼 모듈이나 네임스페이스의 위상-가로지르는 스코프는 추가되는 스코프에서 생략돼요. 이는 참조될 수 있는 바인딩을 제한합니다(따라서 특정 모호한 참조를 피합니다).

이 함수는 syntax-parameterizelocal-require의 구현을 위한 것입니다.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 6.3 버전에서 변경: syntax-parameterizelocal-require에 필요한 최소 기능으로 단순화했습니다.

procedure

(syntax-local-make-delta-introducer id-stx) → procedure?
  id-stx : identifier?

(제한된) 역호환성을 위해서만 있으며, exn:fail:unsupported를 일으켜요.

base 패키지 6.3 버전에서 변경: exn:fail:supported를 일으키도록 변경했습니다.

procedure

(syntax-local-certifier [active?])
  → ((syntax?) (any/c (or/c procedure? #f)) . ->* . syntax?)
  active? : boolean? = #f

역호환성을 위해서만 있으며, 첫 인자를 반환하는 프로시저를 반환해요.

확장 상태 질의 (Expansion State Queries)

procedure

(syntax-transforming?) → boolean?

확장기가 구문 트랜스포머를 적용하는 동적 범위 동안과 모듈이 방문되는 동안 #t, 그 외에는 #f를 반환해요.

procedure

(syntax-transforming-with-lifts?) → boolean?

(syntax-transforming?)#t를 만들고 syntax-local-lift-expression으로 표현식을 끌어올릴 대상 문맥을 이용할 수 있으면 #t, 그 외에는 #f를 반환해요.

현재 (syntax-transforming?)(syntax-transforming-with-lifts?)를 암시해요.

base 패키지 6.3.0.9 버전에서 추가.

procedure

(syntax-transforming-module-expression?) → boolean?

확장기가 모듈 형식 안의 표현식에 대해 구문 트랜스포머를 적용하는 동적 범위 동안 #t, 그 외에는 #f를 반환해요.

procedure

(syntax-local-compiling-module?) → boolean?

module-begin 문맥에서 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안이고, 확장이 컴파일된 모듈을 직접 반환할 수 있는 컴파일 과정의 일부일 때 #t, 그 외에는 #f를 반환해요. module도 보세요.

base 패키지 8.13.0.7 버전에서 추가.

procedure

(syntax-local-identifier-as-binding  id-stx
                                    [ intdef-ctx])   →   identifier?
  id-stx : identifier?
  intdef-ctx : (or/c internal-definition-context? #f) = #f

id-stx와 같지만, 매크로 확장의 일부로서 이전에 식별자에 추가된 사용-지점 스코프가 없는 식별자를 반환해요. intdef-ctx가 내부-정의 문맥이면, 그 문맥에서의 확장 중 만들어진 사용-지점 스코프를 제거해요. #f(기본값)이면 현재 확장 문맥에서의 확장 중 만들어진 사용-지점 스코프를 제거해요.

표현식이 아닌 문맥에서 실행되고 local-expand로 하위 형식의 확장을 강제하는 구문 트랜스포머에서, 확장에서 온 식별자를 바인딩 위치로 옮기거나 bound-identifier=?로 비교하기 전에 syntax-local-identifier-as-binding을 사용해요. 그렇지 않으면 결과가 같은 정의 문맥에서 define이 동작하는 방식과 일관되지 않을 수 있어요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

base 패키지 6.3 버전에서 추가. 8.2.0.7 버전에서 변경: 선택적 intdef-ctx 인자를 추가했습니다.

procedure

(syntax-local-introduce stx) → syntax?
  stx : syntax?

stx와 같지만, 현재 확장을 위한 스코프들—매크로-도입 스코프와 있다면 사용-지점 스코프 둘 다—의 존재가 구문 객체의 모든 부분에서 뒤집힌 구문 객체를 만들어요. 매크로-도입 스코프와 사용-지점 스코프에 대한 정보는 Transformer Bindings를 보세요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요.

예:

> (module example racket
    (define-syntax (require-math stx)
      (syntax-local-introduce #'(require racket/math)))
    (require-math)
    pi)

스코프 도입기 (Scope Introducers)

procedure

(make-syntax-introducer [as-use-site?])
  → ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?)
  as-use-site? : any/c = #f

새 스코프를 캡슐화하고 그것을 주어진 구문 객체에서 뒤집거나, 추가하거나, 제거하는 프로시저를 만들어요. 기본적으로 새 스코프는 매크로-도입 스코프이지만, as-use-site?에 참 값을 제공하면 사용-지점 스코프 같은 스코프를 만들어요. 차이는 syntax-original?이 그 스코프들을 대하는 방식에 있어요.

생성된 프로시저의 동작은 'flip(기본값, 주어진 구문 객체의 각 부분에서 스코프의 존재를 뒤집음), 'add(이미 있는지와 무관하게 각 부분에 스코프를 추가함), 'remove(현재 어떤 부분에 있으면 스코프를 제거함)일 수 있어요.

같은 make-syntax-introducer 결과 프로시저의 여러 적용은 같은 스코프를 사용하고, 다른 결과 프로시저는 구별되는 스코프를 사용해요.

base 패키지 6.3 버전에서 변경: 선택적 as-use-site? 인자를 추가하고, 결과 프로시저에 선택적 연산 인자를 추가했습니다.

procedure

(make-interned-syntax-introducer key)
  → ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?)
  key : (and/c symbol? symbol-interned?)

make-syntax-introducer와 같지만, 캡슐화된 스코프가 **interned 스코프(interned scope)**예요. 같은 keymake-interned-syntax-introducer를 여러 번 호출하면 위상과 모듈 인스턴스화를 가로질러서도 같은 스코프를 뒤집거나, 추가하거나, 제거하는 프로시저를 만들게 돼요. 게다가 그 스코프는 컴파일된 코드에 박혀 있을 때도 일관성을 유지해, make-interned-syntax-introducer로 만든 스코프는 컴파일된 코드에서 불러온 구문 객체에서도 그 동일성을 유지해요. (이런 의미에서 make-syntax-introducermake-interned-syntax-introducer의 관계는 gensymquote의 관계와 비슷해요.)

이 함수는 단일 위상 안의 분리된 바인딩 공간 구현을 위한 것이며, 각 환경과 연관된 스코프는 모듈들 사이에서 같아야 해요.

make-syntax-introducer와 달리, make-interned-syntax-introducer로 만든 프로시저가 추가하는 스코프는 항상 매크로-도입 스코프가 아니라 사용-지점 스코프처럼 취급돼요. 따라서 syntax-original?이 보고하는 originalness에 영향을 주지 않아요.

base 패키지 6.90.0.28 버전에서 추가. 8.2.0.4 버전에서 변경: key가 interned되어야 한다는 제약을 추가했습니다.

procedure

(make-syntax-delta-introducer  ext-stx
                               base-stx
                               [ phase-level])
  → ((syntax?) ((or/c 'flip 'add 'remove)) . ->* . syntax?)
  ext-stx : identifier?
  base-stx : (or/c syntax? #f)
  phase-level : (or/c #f exact-integer?) = (syntax-local-phase-level)

make-syntax-introducer의 결과처럼 동작하지만, ext-stx의 스코프 집합을 사용하고 기본 동작이 'add인 프로시저를 만들어요.

  • base-stx의 스코프가 ext-stx의 스코프의 부분 집합이면, make-syntax-delta-introducer의 결과는 ext-stx의 집합에는 있지만 base-stx의 집합에는 없는 스코프를 추가하거나, 제거하거나, 뒤집어요.
  • base-stx의 스코프가 ext-stx의 스코프의 부분 집합이 아니지만 바인딩이 있으면, 바인딩과 연관된 스코프 집합을 ext-stx의 스코프 집합에서 뺀 뒤, make-syntax-delta-introducer의 결과가 그 차이를 추가하거나, 제거하거나, 뒤집어요.

base-stx에 대한 #f 값은 스코프가 없는 구문 객체와 동등해요.

이 절차는 어떤 m-id가 어떤 orig-id를 기록하는 트랜스포머 바인딩을 가지고 m-id의 사용이 orig-id의 바인딩을 도입할 때 유용할 수 있어요. 그 경우 m-id의 바인딩 이후 m-id의 사용에 추가된 스코프들이 orig-id의 바인딩 인스턴스로 옮겨져, m-id의 사용과 같은 어휘 문맥을 가진 사용을 포착해야 해요.

ext-stx가 tainted이면, 만들어진 프로시저의 식별자 결과가 tainted돼요.

provide 트랜스포머 문맥 (Provide Transformer Context)

procedure

(syntax-local-transforming-module-provides?) → boolean?

제공 트랜스포머(make-provide-transformer 참조)가 실행 중이거나 #%provide의 확장 하위 형식이 확장되는 동안 #t, 그 외에는 #f를 반환해요.

procedure

(syntax-local-module-defined-identifiers)
  → (and/c hash? immutable?)

syntax-local-transforming-module-provides?#t를 반환하는 동안에만 호출될 수 있어요.

위상-레벨 번호(예: 0)를 확장 중인 모듈 안의 해당 위상 레벨의 모든 정의 목록에 매핑하는 해시 테이블을 반환해요. 이 정보는 all-defined-out 같은 provide 하위 형식을 구현하는 데 사용돼요.

유의: 위상-레벨 키는 현재 트랜스포머 위상 레벨(syntax-local-phase-level)을 기준으로 하지 않고 둘러싼 모듈을 기준으로 절대적이에요.

procedure

(syntax-local-module-required-identifiers  mod-path
                                           shift)
  → (or/c (listof (cons/c phase+space?
                          (listof identifier?)))
          #f)
  mod-path : (or/c module-path? #f)
  shift : (or/c #t phase+space-shift?)

syntax-local-transforming-module-provides?#t를 반환하는 동안에만 호출될 수 있어요.

위상 레벨과 바인딩 공간 조합을 식별자 목록에 매핑하는 연관 목록을 반환해요. 각 식별자 목록은 모듈 경로 mod-path를 사용해 (확장 중인 모듈로) 임포트된 모든 바인딩을 포함하고, mod-path#f이면 모든 모듈을 포함해요. 연관 목록은 shift가 나타내는 위상 레벨 및 바인딩 공간 이동으로 임포트된 모든 식별자를 포함하고, shift#t이면 모든 이동을 포함해요. shift#t가 아니면, 그 이동에서 임포트된 식별자가 없으면 결과가 #f일 수 있어요.

식별자가 임포트 시 리네임되면, 결과 연관 목록은 그 식별자를 내부 이름으로 포함해요. 식별자에 대한 추가 정보는 identifier-binding을 사용해 얻어요.

유의: 위상-레벨 이동은 현재 트랜스포머 위상 레벨(syntax-local-phase-level)을 기준으로 하지 않고 둘러싼 모듈을 기준으로 절대적이에요.

base 패키지 8.2.0.3 버전에서 변경: 이동과 결과를 위상–공간 조합으로 일반화했습니다.

조직 낙인 및 자유로운 정의 (Marks and Liberal Define Contexts)

value

prop:liberal-define-context : struct-type-property?

procedure

(liberal-define-context? v) → boolean?
  v : any/c

prop:liberal-define-context 속성에 대해 참 값을 가진 구조체 타입의 인스턴스는 syntax-local-context의 결과나 local-expand의 두 번째 인자에서 내부-정의 문맥 표현의 요소로 사용될 수 있어요. 그런 값은 그 문맥이 define 형식을 잠재적으로 여러 개의 define-valuesdefine-syntaxes 형식으로 자유롭게 확장하는 것을 지원함을 나타내요. 'module'module-body 문맥은 암시적으로 자유로운 확장을 허용해요.

liberal-define-context? 술어는 vprop:liberal-define-context 속성에 대해 참 값을 가진 구조체의 인스턴스이면 #t, 그 외에는 #f를 반환해요.

12.4.1 require 트랜스포머 (require Transformers)

(require racket/require-transform)  package: base

이 섹션에서 문서화된 바인딩은 racket/baseracket이 아니라 racket/require-transform 라이브러리가 제공해요.

값이 prop:require-transformer 속성을 가진 구조체인 트랜스포머 바인딩은 require용 파생 require-spec을 require 트랜스포머로 구현해요.

require 트랜스포머는 require 형식 안에서 require-spec으로서의 사용을 나타내는 구문 객체와 함께 호출되고, 결과는 두 목록이어야 해요: 임포트 목록과 임포트-소스 목록.

파생 형식이 require-spec인 하위 형식을 포함하면, expand-import를 호출해 하위 require-spec을 임포트와 임포트 소스 목록으로 변형할 수 있어요.

매크로 스타일의 require 트랜스포머를 지원하는 define-require-syntax도 보세요.

procedure

(expand-import require-spec)
  → (listof import?)  (listof import-source?)
  require-spec : syntax?

주어진 require-spec을 임포트와 임포트 소스 목록으로 확장해요. 후자는 인스턴스화되거나 방문되어야 할 모듈을 지정하며, 그래서 그것이 나타내는 모듈은 전자 목록이 나타내는 모듈의 상위 집합이어야 해요(그래서 모든 임포트가 결국 전자 목록에서 걸러져도 모듈은 인스턴스화되거나 방문됩니다).

procedure

(make-require-transformer proc) → require-transformer?
  proc : (syntax? . -> . (values
                          (listof import?)
                          (listof import-source?)))

주어진 프로시저를 트랜스포머로 사용해 require 트랜스포머를 만들어요. 흔히 expand-import와 함께 사용돼요.

예:

> (require (for-syntax racket/require-transform))

> (define-syntax printing
    (make-require-transformer
     (lambda (stx)
       (syntax-case stx ()
         [(_ path)
          (begin
            (printf "Importing: ~a~n" #'path)
            (expand-import #'path))]))))
> (require (printing racket/match))
Importing: #<syntax:eval:37:0 racket/match>

value

prop:require-transformer : struct-type-property?

require 트랜스포머를 식별하는 속성이에요. 속성 값은 구조체를 받아 트랜스포머 프로시저를 반환하는 프로시저여야 해요. 반환된 트랜스포머 프로시저는 구문 객체를 받아 임포트와 임포트-소스 목록을 반환해요.

procedure

(require-transformer? v) → boolean?
  v : any/c

vprop:require-transformer 속성을 가지면 #t, 그 외에는 #f를 반환해요.

struct

(struct  import  ( local-id
                   src-sym
                   src-mod-path
                   mode
                   req-mode
                   orig-mode
                   orig-stx)
  #:extra-constructor-name make-import)
  local-id : identifier?
  src-sym : symbol?
  src-mod-path : (or/c module-path?
                       (syntax/c module-path?))
  mode : phase+space?
  req-mode : phase+space-shift?
  orig-mode : phase+space?
  orig-stx : syntax?

단일 임포트된 식별자를 나타내는 구조체예요:

  • local-id — 임포트하는 모듈 안에서 바인딩될 식별자. 단 mode가 암시하는 공간 특정 스코프는 없어요.
  • src-sym — 소스 모듈에서 내보낸 바인딩의 외부 이름.
  • src-mod-path — 임포트된 바인딩의 소스에 대한 (임포트하는 모듈 기준의) 모듈 경로.
  • mode — 임포트하는 모듈에서 바인딩의 위상 레벨과 바인딩 공간. (phase+space+ orig-mode req-mode)와 같아야 해요.
  • req-mode — 내보내는 모듈 기준의 임포트의 위상 레벨 이동과 바인딩 공간 이동.
  • orig-mode — 내보내는 모듈이 내보낸 바인딩의 위상 레벨과 바인딩 공간.
  • orig-stx — 오류 보고에 사용하는 임포트 소스용 구문 객체.

base 패키지 8.2.0.3 버전에서 변경: 모드를 위상–공간 조합으로 일반화했습니다.

struct

(struct  import-source (mod-path-stx mode)
  #:extra-constructor-name make-import-source)
  mod-path-stx : (syntax/c module-path?)
  mode : phase+space-shift?

임포트된 모듈을 나타내는 구조체로, 어떤 바인딩도 모듈로 임포트되지 않아도 인스턴스화되거나 방문되어야 해요.

  • mod-path-stx — 임포트된 바인딩의 소스에 대한 (임포트하는 모듈 기준의) 모듈 경로.
  • mode — 임포트의 위상 레벨 이동과 바인딩 공간 이동.

base 패키지 8.2.0.3 버전에서 변경: 모드를 위상–공간 조합으로 일반화했습니다.

parameter

(current-require-module-path) → (or/c #f module-path-index?)
(current-require-module-path module-path) → void?
  module-path : (or/c #f module-path-index?)

상대 require-레벨 모듈 경로가 convert-relative-module-path(모든 내장 require 하위 형식이 암시적으로 사용)에 의해 #%require-레벨 모듈 경로로 어떻게 확장되는지 결정하는 파라미터예요.

current-require-module-path의 값이 #f이면 상대 모듈 경로는 그대로 남겨져요. 즉 require 문맥이 모듈 경로의 해석을 결정한다는 뜻이에요.

require 형식은 하위 형식 트랜스포머를 호출하는 동안 current-require-module-path#f로 파라미터화하고, relative-in은 주어진 모듈 경로로 파라미터화해요.

procedure

(convert-relative-module-path module-path)
  → (or/c module-path?
          (syntax/c module-path?))
  module-path : (or/c module-path?
                      (syntax/c module-path?))

current-require-module-path에 따라 module-path를 변환해요.

module-path가 상대가 아니거나 current-require-module-path의 값이 #f이면 module-path가 반환돼요. 그 외에는 current-require-module-path 값 기준의 module-path와 동등한 절대 모듈 경로로 변환돼요.

procedure

(syntax-local-lift-require-top-level-form top-level-stx)
  → void?
  top-level-stx : syntax?

top-level-stx를 확장 중인 require 바로 뒤에 이어서 둘러싼 모듈의 최상위로 끌어올려요.

이 절차는 확장기가 구문 트랜스포머를 적용하는 동적 범위 동안, 또는 모듈이 방문되는 동안 호출되어야 해요(syntax-transforming? 참조). 그렇지 않으면 exn:fail:contract 예외가 발생해요. 추가로 이 절차는 require 트랜스포머를 확장하는 동안에만 호출될 수 있어요.

base 패키지 8.12.0.13 버전에서 추가.

procedure

(syntax-local-require-certifier)
  → ((syntax?) (or/c #f (syntax? . -> . syntax?)) . ->* . syntax?)

역호환성을 위해서만 있으며, 첫 인자를 반환하는 프로시저를 반환해요.

12.4.2 provide 트랜스포머 (provide Transformers)

(require racket/provide-transform)  package: base

이 섹션에서 문서화된 바인딩은 racket/baseracket이 아니라 racket/provide-transform 라이브러리가 제공해요.

값이 prop:provide-transformer 속성을 가진 구조체인 트랜스포머 바인딩은 provide용 파생 provide-spec을 provide 트랜스포머로 구현해요. provide 트랜스포머는 모듈 확장의 마지막 단계의 일부로, 모듈 안의 다른 모든 선언과 표현식이 확장된 뒤에 적용돼요.

값이 prop:provide-pre-transformer 속성을 가진 구조체인 트랜스포머 바인딩은 provide용 파생 provide-spec을 **provide 사전-트랜스포머(pre-transformer)**로 구현해요. provide 사전-트랜스포머는 모듈 확장의 첫 단계의 일부로 적용돼요. 첫 단계에서 사용되므로, provide 사전-트랜스포머는 syntax-local-lift-expression 같은 함수를 사용해 둘러싼 모듈에 표현식과 정의를 도입할 수 있어요.

어떤 식별자는 provide 트랜스포머와 provide 사전-트랜스포머 양쪽으로 동작하는 값에 대한 트랜스포머 바인딩을 가질 수 있어요. provide 사전-트랜스포머의 결과는 자동으로 재확장되지 않으므로, provide 사전-트랜스포머는 그 경우 유용하게 자기 자신으로 확장될 수 있어요.

트랜스포머는 provide 형식 안에서 provide-spec으로서의 사용을 나타내는 구문 객체와, 둘러싼 provide-spec이 지정한 내보내기 모드를 나타내는 심볼 목록과 함께 호출돼요. provide 트랜스포머의 결과는 export 목록이어야 하고, provide 사전-트랜스포머의 결과는 모듈 확장의 마지막 단계에서 provide-spec으로 쓰일 구문 객체예요.

파생 형식이 provide-spec인 하위 형식을 포함하면, 하위 provide-spec 하위 형식을 변형하기 위해 expand-exportpre-expand-export를 호출할 수 있어요.

매크로 스타일의 provide 트랜스포머를 지원하는 define-provide-syntax도 보세요.

procedure

(expand-export provide-spec modes) → (listof export?)
  provide-spec : syntax?
  modes : (listof phase+space?)

주어진 provide-spec을 export 목록으로 확장해요. modes 목록은 하위 provide-spec의 확장을 통제해요. 예를 들어 식별자는 modes 목록이 달리 지정하지 않는 한 둘러싼 provide 형식의 위상 레벨의 바인딩을 참조해요. 보통 modes는 비어 있거나 단일 요소를 담아요.

base 패키지 8.2.0.3 버전에서 변경: 모드를 위상–공간 조합으로 일반화했습니다.

procedure

(pre-expand-export provide-spec modes) → syntax?
  provide-spec : syntax?
  modes : (listof phase+space?)

주어진 provide-spec을 provide 사전-트랜스포머 수준에서 확장해요. modes 인자는 expand-export에서와 같아요.

base 패키지 8.2.0.3 버전에서 변경: 모드를 위상–공간 조합으로 일반화했습니다.

procedure

(make-provide-transformer proc) → provide-transformer?
  proc : (syntax? (listof phase+space?)
          . -> . (listof export?))
(make-provide-transformer proc pre-proc)
  → (and/c provide-transformer? provide-pre-transformer?)
  proc : (syntax? (listof phase+space?)
          . -> . (listof export?))
  pre-proc : (syntax? (listof phase+space?)
              . -> . syntax?)

주어진 프로시저를 트랜스포머로 사용해 provide 트랜스포머(즉 prop:provide-transformer 속성을 가진 구조체)를 만들어요. pre-proc가 제공되면 결과는 provide 사전-트랜스포머이기도 해요. 흔히 expand-export 및/또는 pre-expand-export와 함께 사용돼요.

procedure

(make-provide-pre-transformer pre-proc)
  → provide-pre-transformer?
  pre-proc : (syntax? (listof phase+space?)
              . -> . syntax?)

make-provide-transformer와 같지만, provide 사전-트랜스포머인 값만을 위한 것이에요. 흔히 pre-expand-export와 함께 사용돼요.

예:

> (module m racket
    (require
      (for-syntax racket/provide-transform syntax/parse syntax/stx))

    (define-syntax wrapped-out
      (make-provide-pre-transformer
        (lambda (stx modes)
          (syntax-parse stx
            [(_ f ...)
             #:with (wrapped-f ...)
             (stx-map
               syntax-local-lift-expression
               #'((lambda args
                     (printf "applying ~a, args: ~a\n" 'f args)
                     (apply f args)) ...))
             (pre-expand-export
               #'(rename-out [wrapped-f f] ...) modes)]))))

    (provide (wrapped-out + -)))
> (require 'm)
> (- 1 (+ 2 3))

applying +, args: (2 3)

applying -, args: (1 5)

-4

value

prop:provide-transformer : struct-type-property?

provide 트랜스포머를 식별하는 속성이에요. 속성 값은 구조체를 받아 트랜스포머 프로시저를 반환하는 프로시저여야 해요. 반환된 트랜스포머 프로시저는 구문 객체와 모드 목록을 받아 export 목록을 반환해요.

value

prop:provide-pre-transformer : struct-type-property?

provide 사전-트랜스포머를 식별하는 속성이에요. 속성 값은 구조체를 받아 트랜스포머 프로시저를 반환하는 프로시저여야 해요. 반환된 트랜스포머 프로시저는 구문 객체와 모드 목록을 받아 구문 객체를 반환해요.

procedure

(provide-transformer? v) → boolean?
  v : any/c

vprop:provide-transformer 속성을 가지면 #t, 그 외에는 #f를 반환해요.

procedure

(provide-pre-transformer? v) → boolean?
  v : any/c

vprop:provide-pre-transformer 속성을 가지면 #t, 그 외에는 #f를 반환해요.

struct

(struct  export (local-id out-id mode protect? orig-stx)
  #:extra-constructor-name make-export)
  local-id : identifier?
  out-id : identifier?
  mode : phase+space?
  protect? : any/c
  orig-stx : syntax?

단일 내보낸 식별자를 나타내는 구조체예요:

  • local-id — 내보내는 모듈 안에서 바인딩된 식별자.
  • out-id — 바인딩의 외부 이름.
  • mode — 내보내기의 위상 레벨과 바인딩 공간(임포트되는 방식에 영향을 줌).
  • protect? — 식별자를 보호해야 하는지 여부(Code Inspectors 참조).
  • orig-stx — 오류 보고에 사용하는 내보내기 소스용 구문 객체.

base 패키지 8.2.0.3 버전에서 변경: 모드를 위상–공간 조합으로 일반화했습니다.

base 패키지 8.9.0.5 버전에서 변경: out-sym 필드를 out-id로 변경했습니다. 역호환성을 위해 make-export 생성자가 심볼도 받고, export-out-sym 함수가 out-idsyntax-e 값을 반환합니다.

procedure

(export-out-sym ex) → symbol?
  ex : export?

syntax-eexport-out-id와 합성해요.

이 함수는 역호환성을 위한 것입니다. 대신 export-out-id를 직접 사용하세요.

base 패키지 8.9.0.5 버전에서 추가.

procedure

(syntax-local-provide-certifier)
  → ((syntax?) (or/c #f (syntax? . -> . syntax?)) . ->* . syntax?)

역호환성을 위해서만 있으며, 첫 인자를 반환하는 프로시저를 반환해요.

12.4.3 키워드-인자 변환 내부 (Keyword-Argument Conversion Introspection)

(require racket/keyword-transform)  package: base

이 섹션에서 문서화된 바인딩은 racket/baseracket이 아니라 racket/keyword-transform 라이브러리가 제공해요.

procedure

(syntax-procedure-alias-property stx)
  → (or/c #f
          (letrec ([val? (recursive-contract
                          (or/c (cons/c identifier? identifier?)
                                (cons/c val? val?)))])
            val?))
  stx : syntax?

procedure

(syntax-procedure-converted-arguments-property stx)
  → (or/c #f
          (letrec ([val? (recursive-contract
                          (or/c (cons/c identifier? identifier?)
                                (cons/c val? val?)))])
            val?))
  stx : syntax?

키워드-적용 형식의 확장이 식별자에 붙일 수 있는 구문 속성의 값을 보고해요. 속성에 대한 자세한 내용은 lambda를 보세요.

속성 값은 보통 원래 식별자와 확장에 나타나는 식별자로 이뤄진 쌍이에요. syntax-track-origin을 통한 속성-값 병합은 그 값을 그런 값들의 쌍으로 만들 수 있고, 이어서 계속돼요.

12.4.4 포털 구문 바인딩 (Portal Syntax Bindings)

make-portal-syntax가 만든 포털 구문 값에 바인딩된 식별자는 트랜스포머로 동작하지 않지만, 둘러싼 모듈을 인스턴스화하지 않고도 접근·검사할 수 있는 구문 객체를 캡슐화해요. 포털 구문은 또한 #%requireportal 형식으로 바인딩돼요.

procedure

(portal-syntax? v) → boolean?
  v : any/c

vmake-portal-syntax가 만든 값이면 #t, 그 외에는 #f를 반환해요.

base 패키지 8.3.0.8 버전에서 추가.

procedure

(make-portal-syntax stx) → portal-syntax?
  stx : syntax?

내용이 stx인 포털 구문을 만들어요.

define-syntaxdefine-syntaxes가 모듈 본문에서 식별자를 포털 구문에 즉시 바인딩하면, 확장 중 syntax-local-value로 접근할 수 있는 것에 더해 그 포털 구문 내용은 identifier-binding-portal-syntax로도 접근할 수 있어요.

base 패키지 8.3.0.8 버전에서 추가.

procedure

(portal-syntax-content portal) → syntax?
  portal : portal-syntax?

make-portal-syntax로 만든 포털 구문의 내용을 반환해요.

base 패키지 8.3.0.8 버전에서 추가.

더 알아보기