Skip to content

Commit eb31bdd

Browse files
authored
Merge pull request #1403 from herbie-fp/test-something
Refactor platform language keyword handling
2 parents c6c7da7 + 1aef2a1 commit eb31bdd

File tree

1 file changed

+91
-92
lines changed

1 file changed

+91
-92
lines changed

src/syntax/platform-language.rkt

Lines changed: 91 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -84,124 +84,123 @@
8484
[(list arg ...) (map loop arg)]
8585
[_ ctx])))
8686

87-
(define/contract (create-operator-impl! name
88-
ctx
89-
spec
90-
#:impl [fl-proc #f]
91-
#:fpcore [fpcore #f]
92-
#:cost [cost #f])
93-
(->* (symbol? context? any/c)
94-
(#:impl (or/c procedure? generator? #f) #:fpcore any/c #:cost (or/c #f real? procedure?))
95-
operator-impl?)
96-
;; check specification
97-
(check-spec! name ctx spec)
98-
;; synthesize operator (if the spec contains exactly one operator)
99-
(define op
100-
(match spec
101-
[(list op (or (? number?) (? symbol?)) ...) op]
102-
[_ #f]))
103-
;; check FPCore translation
104-
(match (fpcore-parameterize (or fpcore spec))
87+
(define (check-fpcore! name fpcore)
88+
(match (fpcore-parameterize fpcore)
10589
[`(! ,props ... (,op ,args ...))
10690
(unless (even? (length props))
107-
(error 'create-operator-impl! "~a: umatched property in ~a" name fpcore))
91+
(error 'define-operation "~a: unmatched property in ~a" name fpcore))
10892
(unless (symbol? op)
109-
(error 'create-operator-impl! "~a: expected symbol `~a`" name op))
93+
(error 'define-operation "~a: expected symbol `~a`" name op))
11094
(for ([arg (in-list args)]
11195
#:unless (or (symbol? arg) (number? arg)))
112-
(error 'create-operator-impl! "~a: expected terminal `~a`" name arg))]
96+
(error 'define-operation "~a: expected terminal `~a`" name arg))]
11397
[`(,op ,args ...)
11498
(unless (symbol? op)
115-
(error 'create-operator-impl! "~a: expected symbol `~a`" name op))
99+
(error 'define-operation "~a: expected symbol `~a`" name op))
116100
(for ([arg (in-list args)]
117101
#:unless (or (symbol? arg) (number? arg)))
118-
(error 'create-operator-impl! "~a: expected terminal `~a`" name arg))]
102+
(error 'define-operation "~a: expected terminal `~a`" name arg))]
119103
[(? symbol?) (void)]
120-
[_ (error 'create-operator-impl! "Invalid fpcore for ~a: ~a" name fpcore)])
121-
;; check or synthesize floating-point operation
104+
[_ (error 'define-operation "Invalid fpcore for ~a: ~a" name fpcore)]))
105+
106+
(define (check-fl-proc! name ctx fl-proc spec)
122107
(define fl-proc*
123108
(match fl-proc
124109
[(? generator?) ((generator-gen fl-proc) spec ctx)]
125-
[(? procedure?) fl-proc]
126-
[#f (error 'create-operator-impl! "fl-proc is not provided for `~a` implementation" name)]))
110+
[(? procedure?) fl-proc]))
127111
(unless (procedure-arity-includes? fl-proc* (length (context-vars ctx)) #t)
128-
(error 'arity-check
112+
(error 'define-operation
129113
"Procedure `~a` accepts ~a arguments, but ~a is provided"
130114
name
131115
(procedure-arity fl-proc*)
132116
(length (context-vars ctx))))
133-
(define-values (cost* aggregate*)
134-
(cond
135-
[(number? cost) (values cost +)]
136-
[(procedure? cost) (values 0 cost)]
137-
[else (values cost +)]))
138-
(operator-impl name ctx spec (fpcore-parameterize (or fpcore spec)) fl-proc* cost* aggregate*))
117+
fl-proc*)
118+
119+
(define (check-cost! name cost)
120+
(match cost
121+
[(? number?) (values cost +)]
122+
[(? procedure?) (values 0 cost)]
123+
[_ (error 'define-operation "Invalid cost for ~a: ~a" name cost)]))
124+
125+
(define/contract (create-operator-impl! name
126+
ctx
127+
#:spec spec
128+
#:impl fl-proc
129+
#:fpcore fpcore
130+
#:cost cost)
131+
(-> symbol?
132+
context?
133+
#:spec any/c
134+
#:impl (or/c procedure? generator?)
135+
#:fpcore any/c
136+
#:cost (or/c real? procedure?)
137+
operator-impl?)
138+
(check-spec! name ctx spec)
139+
(check-fpcore! name fpcore)
140+
(define fl-proc* (check-fl-proc! name ctx fl-proc spec))
141+
(define-values (cost* aggregate*) (check-cost! name cost))
142+
(operator-impl name ctx spec (fpcore-parameterize fpcore) fl-proc* cost* aggregate*))
143+
144+
;; Generic keyword parser for syntax (at compile-time)
145+
(begin-for-syntax
146+
(define (parse-keyword-fields stx fields-stx allowed-keywords op-name)
147+
(define (oops! why [sub-stx #f])
148+
(raise-syntax-error op-name why stx sub-stx))
149+
150+
(define result-hash (make-hasheq))
151+
152+
(let loop ([fields fields-stx])
153+
(syntax-case fields ()
154+
[() result-hash]
155+
[(kw val rest ...)
156+
(keyword? (syntax-e #'kw))
157+
(let ([kw-sym (string->symbol (keyword->string (syntax-e #'kw)))])
158+
(unless (member kw-sym allowed-keywords)
159+
(oops! (format "unknown keyword ~a" (syntax-e #'kw)) #'kw))
160+
(when (hash-has-key? result-hash kw-sym)
161+
(oops! (format "multiple ~a clauses" (syntax-e #'kw)) #'kw))
162+
(hash-set! result-hash kw-sym #'val)
163+
(loop #'(rest ...)))]
164+
[(kw)
165+
(keyword? (syntax-e #'kw))
166+
(oops! (format "expected value after keyword ~a" (syntax-e #'kw)) #'kw)]
167+
[_ (oops! "bad syntax" fields)]))))
139168

140169
(define-syntax (make-operator-impl stx)
141170
(define (oops! why [sub-stx #f])
142171
(raise-syntax-error 'make-operator-impl why stx sub-stx))
143172
(syntax-case stx (:)
144-
[(_ (id [var : repr] ...) rtype fields ...)
145-
(let ([id #'id]
146-
[vars (syntax->list #'(var ...))]
147-
[fields #'(fields ...)])
148-
(unless (identifier? id)
149-
(oops! "expected identifier" id))
173+
[(_ (id [var : repr] ...) rtype . fields)
174+
(let ([op-name #'id]
175+
[vars (syntax->list #'(var ...))])
176+
(unless (identifier? op-name)
177+
(oops! "expected identifier" op-name))
150178
(for ([var (in-list vars)]
151179
#:unless (identifier? var))
152180
(oops! "expected identifier" var))
153-
(define spec #f)
154-
(define core #f)
155-
(define fl-expr #f)
156-
(define op-cost #f)
157-
158-
(let loop ([fields fields])
159-
(syntax-case fields ()
160-
[()
161-
(unless spec
162-
(oops! "missing `#:spec` keyword"))
163-
(with-syntax ([id id]
164-
[spec spec]
165-
[core core]
166-
[fl-expr fl-expr]
167-
[op-cost op-cost])
168-
#'(create-operator-impl! 'id
169-
(context '(var ...) rtype (list repr ...))
170-
'spec
171-
#:impl fl-expr
172-
#:fpcore 'core
173-
#:cost op-cost))]
174-
[(#:spec expr rest ...)
175-
(cond
176-
[spec (oops! "multiple #:spec clauses" stx)]
177-
[else
178-
(set! spec #'expr)
179-
(loop #'(rest ...))])]
180-
[(#:spec) (oops! "expected value after keyword `#:spec`" stx)]
181-
[(#:fpcore expr rest ...)
182-
(cond
183-
[core (oops! "multiple #:fpcore clauses" stx)]
184-
[else
185-
(set! core #'expr)
186-
(loop #'(rest ...))])]
187-
[(#:fpcore) (oops! "expected value after keyword `#:fpcore`" stx)]
188-
[(#:impl expr rest ...)
189-
(cond
190-
[fl-expr (oops! "multiple #:fl clauses" stx)]
191-
[else
192-
(set! fl-expr #'expr)
193-
(loop #'(rest ...))])]
194-
[(#:impl) (oops! "expected value after keyword `#:fl`" stx)]
195-
[(#:cost cost rest ...)
196-
(cond
197-
[op-cost (oops! "multiple #:cost clauses" stx)]
198-
[else
199-
(set! op-cost #'cost)
200-
(loop #'(rest ...))])]
201-
[(#:cost) (oops! "expected value after keyword `#:cost`" stx)]
202-
203-
; bad
204-
[_ (oops! "bad syntax" fields)])))]
181+
182+
(define keywords (parse-keyword-fields stx #'fields '(spec fpcore impl cost) op-name))
183+
184+
(unless (hash-has-key? keywords 'spec)
185+
(raise-syntax-error op-name "missing `#:spec` keyword" stx))
186+
(unless (hash-has-key? keywords 'impl)
187+
(raise-syntax-error op-name "missing `#:impl` keyword" stx))
188+
(unless (hash-has-key? keywords 'cost)
189+
(raise-syntax-error op-name "missing `#:cost` keyword" stx))
190+
191+
;; Build argument list for create-operator-impl!
192+
;; Quote spec and fpcore, leave impl and cost unquoted
193+
;; Default fpcore to spec if not provided
194+
(with-syntax ([spec-val (hash-ref keywords 'spec)]
195+
[fpcore-val (hash-ref keywords 'fpcore (hash-ref keywords 'spec))]
196+
[impl-val (hash-ref keywords 'impl)]
197+
[cost-val (hash-ref keywords 'cost)])
198+
#'(create-operator-impl! 'id
199+
(context '(var ...) rtype (list repr ...))
200+
#:spec 'spec-val
201+
#:impl impl-val
202+
#:fpcore 'fpcore-val
203+
#:cost cost-val)))]
205204
[_ (oops! "bad syntax")]))
206205

207206
;; Platform registration functions moved from platform.rkt

0 commit comments

Comments
 (0)