-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathdemo.rkt
101 lines (85 loc) · 3.5 KB
/
demo.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#lang racket
(require (for-syntax syntax/parse racket/port))
(begin-for-syntax
;; Editing commands are represented as prefab structs.
(struct command (name module-path function arguments) #:prefab))
;; The simplest way to attach TODOs is to attach a string to the 'todo syntax
;; property.
(define-syntax (TODO stx)
(syntax-parse stx
[(_ msg:str)
;; Expand a TODO to a runtime error
(define runtime
(syntax/loc stx
(error msg)))
;; Attach a notice that it is a TODO to be filled out
(syntax-property
(syntax-property
runtime
'todo (syntax->datum #'msg))
'editing-command (command "Replace with error" "test-command.rkt" 'replace-with-error '()))]))
(define x
(+ (TODO "one number")
(TODO "another number")))
(TODO "write more code!")
;; For more control over the placement of TODOs, use the located struct.
;; For the ability to write separate summaries and detailed TODOs, use the todo-item struct.
(begin-for-syntax
(struct located (loc value) #:prefab)
(struct todo-item (full summary) #:prefab))
(require racket/stxparam racket/splicing)
;; This example uses a syntax parameter to propagate the surrounding expression
;; context, attaching the todo-item to the context if one exists.
(define-syntax-parameter definition-context #f)
(define-syntax (define/todos stx)
(syntax-parse stx
[(_ x e)
(with-syntax ([ctx stx])
(syntax/loc stx
(splicing-syntax-parameterize ([definition-context #'ctx])
(define x e))))]))
(define-syntax (inner-TODO stx)
(define ctx (or (syntax-parameter-value #'definition-context) stx))
(syntax-parse stx
[(_ msg:str)
(define item
(located ctx
(todo-item (syntax->datum #'msg)
(syntax-parse ctx
#:literals (define/todos)
[(define/todos x e) (syntax->datum #'x)]
[_ (syntax->datum #'msg)]))))
(syntax-property (syntax/loc stx (error 'inner-todo msg)) 'todo item)]))
;; The entire definition containing the TODO is highlighted as a thing to be done now.
(define/todos incomplete-fun
(lambda (y)
(inner-TODO "This function is incomplete")))
;;; Example of an editing command without a goal.
(define-syntax (with-command stx)
(syntax-case stx ()
[(_ e)
(syntax-property #'e
'editing-command
(command "Double" "test-command.rkt" 'double '()))]))
(with-command 444)
(define-syntax (TODO/bindings stx)
(syntax-case stx ()
[(_ e ...)
;; syntax-debug-info returns information about macro expansion contexts.
;; It will often let you get local variables in #lang racket! See the docs
;; for more information about syntax-debug-info.
(let* ((info (syntax-debug-info stx (syntax-local-phase-level) #t))
(bindings (hash-ref info 'bindings '())))
(let ((details (with-output-to-string
(lambda ()
(printf "Local vars:\n")
(for ([b bindings])
(let ((name (hash-ref b 'name #f))
(local? (hash-ref b 'local #f)))
(when (and name local?)
(printf " ~a\n" name))))))))
(syntax-property #'(error 'TODO/bindings)
'todo (todo-item details "TODO with bindings"))))]))
(let ((x 1) (y 2)) (TODO/bindings))
;; No auto tests here
(module test racket/base)