www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit cf92b0fc32a3bc3009c876332bab7135f379514e
parent e4b3235a596543a8969a950e686b24c003a85f56
Author: Georges Dupéron <georges.duperon@gmail.com>
Date:   Thu, 26 Jan 2017 23:25:05 +0100

Closes FB case 186 Trigger error when stxparse-info is not active (use get-shadower and compare the ids)

Diffstat:
Mmain.rkt | 118+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Atest/test-subtemplate-detect-stxinfo.rkt | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 145 insertions(+), 44 deletions(-)

diff --git a/main.rkt b/main.rkt @@ -4,11 +4,13 @@ phc-toolkit/untyped racket/stxparam stxparse-info/parse + stxparse-info/case stxparse-info/current-pvars stxparse-info/parse/experimental/template syntax/id-table - racket/syntax + (subtract-in racket/syntax stxparse-info/case) (for-syntax "patch-arrows.rkt" + racket/format stxparse-info/parse racket/private/sc racket/syntax @@ -171,53 +173,81 @@ (car depths) #'check-ellipsis-count-ddd)))) -(define-for-syntax/case-args ((sub*template tmpl-form) - (self tmpl . maybe-props)) - (define acc '()) +(define-for-syntax (sub*template self-form tmpl-form) + (syntax-parser + [(self {~optional {~and #:force-no-stxinfo force-no-stxinfo}} + {~optional {~and #:props maybe-props}} + ;; #: marks end of options (so that we can have implicit ?@ later) + {~optional #:} + tmpl) + (unless (attribute force-no-stxinfo) + (for ([sym (in-list '(syntax-parse define/syntax-parse syntax-parser + syntax-case define/with-syntax with-syntax))]) + (let ([shadower (syntax-local-get-shadower (datum->syntax #'self sym))] + [good (datum->syntax #'here sym)]) + (when (or (not (identifier-binding shadower)) + (not (free-identifier=? shadower good))) + (raise-syntax-error self-form + (~a sym (if (identifier-binding shadower) + (~a " resolves to the official " + sym ",") + " seems undefined,") + " but subtemplate needs the patched" + " version from stxparse-info. Use (require" + " stxparse-info/parse) and (require" + " stxparse-info/case) to fix this. This" + " message can be disabled with (" self-form + " #:force-no-stxinfo …), if you know what" + " you're doing.")))))) + + (define acc '()) - ;; Finds identifiers of the form zᵢ, and return a list of existing xᵢ bindings - (define (fold-process stx rec) - (syntax-case stx () - [(id . _) (and (identifier? #'id) - (free-identifier=? #'id #'unsyntax)) - stx] - [id (identifier? #'id) - (let ([binders+info (find-subscript-binder #'id)]) - (when binders+info - (set! acc (cons binders+info acc))) - #'id)] - [other (rec #'other)])) - ;; Process the syntax, extract the derived bindings into acc - ;; Does not take zᵢ identifiers generated by template metafunctions into - ;; account for now. - (fold-syntax fold-process #'tmpl) + ;; Finds identifiers of the form zᵢ, and return a list of existing xᵢ + ;; bindings + (define (fold-process stx rec) + (syntax-case stx () + [(id . _) (and (identifier? #'id) + (free-identifier=? #'id #'unsyntax)) + stx] + [id (identifier? #'id) + (let ([binders+info (find-subscript-binder #'id)]) + (when binders+info + (set! acc (cons binders+info acc))) + #'id)] + [other (rec #'other)])) + ;; Process the syntax, extract the derived bindings into acc + ;; Does not take zᵢ identifiers generated by template metafunctions into + ;; account for now. + (fold-syntax fold-process #'tmpl) - ;; define the result, which looks like (template . tmpl) or - ;; like (quasitemplate . tmpl) - (define result - (quasisyntax/top-loc #'self - (#,tmpl-form tmpl . maybe-props))) - ;; Make sure that we remove duplicates, otherwise we'll get errors if we - ;; define the same derived id twice. - (define/with-syntax ([bound - binders - unique-at-runtime-ids - ellipsis-depth - check-ellipsis-count] - …) - (remove-duplicates acc bound-identifier=? #:key car)) + ;; define the result, which looks like (template . tmpl) or + ;; like (quasitemplate . tmpl) + (define result + (quasisyntax/top-loc #'self + (#,tmpl-form tmpl #,@(when-attr maybe-props #'{#:props maybe-props})))) + ;; Make sure that we remove duplicates, otherwise we'll get errors if we + ;; define the same derived id twice. + (define/with-syntax ([bound + binders + unique-at-runtime-ids + ellipsis-depth + check-ellipsis-count] + …) + (remove-duplicates acc bound-identifier=? #:key car)) - #`(let () - (derive bound binders unique-at-runtime-ids ellipsis-depth) - … - (let () - ;; no-op, just to raise an error when they are incompatible - #'(check-ellipsis-count …) ;; TODO: allow #f values for ~optional in syntax/parse ;;;;;;;;;;;;;; - ;; actually call template or quasitemplate - #,result))) + #`(let () + (derive bound binders unique-at-runtime-ids ellipsis-depth) + … + (let () + ;; no-op, just to raise an error when they are incompatible + #'(check-ellipsis-count …) ;; TODO: allow #f values for ~optional in syntax/parse ;;;;;;;;;;;;;; + ;; actually call template or quasitemplate + #,result))])) -(define-syntax subtemplate (sub*template #'template)) -(define-syntax quasisubtemplate (sub*template #'quasitemplate)) +(define-syntax subtemplate + (sub*template 'subtemplate #'template)) +(define-syntax quasisubtemplate + (sub*template 'quasisubtemplate #'quasitemplate)) (define/contract (multi-hash-ref! h keys to-set) ;; This assumes that the hash does not get mutated during the execution of diff --git a/test/test-subtemplate-detect-stxinfo.rkt b/test/test-subtemplate-detect-stxinfo.rkt @@ -0,0 +1,71 @@ +#lang racket +(module m-ok racket + (require subtemplate + stxparse-info/parse + stxparse-info/case + rackunit + syntax/macro-testing) + (check-not-exn + (λ () + (convert-compile-time-error + (subtemplate ok))))) + +(module m-no-parse racket + (require subtemplate + stxparse-info/case + rackunit + syntax/macro-testing) + (check-exn #rx"subtemplate: syntax-parse seems undefined," + (λ () + (convert-compile-time-error + (subtemplate ok))))) + +(module m-wrong-parse racket + (require subtemplate + syntax/parse + stxparse-info/case + rackunit + syntax/macro-testing) + (check-exn + #rx"subtemplate: syntax-parse resolves to the official syntax-parse," + (λ () + (convert-compile-time-error + (subtemplate ok))))) + +(module m-wrong-case racket + (require subtemplate + stxparse-info/parse + rackunit + syntax/macro-testing) + (check-exn #rx"subtemplate: syntax-case resolves to the official syntax-case," + (λ () + (convert-compile-time-error + (subtemplate ok))))) + +(module m-no-parse-wrong-case racket + (require subtemplate + rackunit + syntax/macro-testing) + (check-exn #rx"subtemplate: syntax-parse seems undefined," + (λ () + (convert-compile-time-error + (subtemplate ok))))) + +(module m-wrong-parse-wrong-case racket + (require subtemplate + syntax/parse + rackunit + syntax/macro-testing) + (check-exn + #rx"subtemplate: syntax-parse resolves to the official syntax-parse," + (λ () + (convert-compile-time-error + (subtemplate ok))))) + + +(require 'm-ok) +(require 'm-no-parse) +(require 'm-wrong-parse) +(require 'm-wrong-case) +(require 'm-no-parse-wrong-case) +(require 'm-wrong-parse-wrong-case)