mildc055ee
2021-12-15 03:13:01

I wrote the code like below: (struct instruction ()) (define-syntax-parser define-instruction [(_ opcode:number name:id (~optional (n:id ...))) #:with instr (format-id #'name "instr:~a" #'name) #:with op (format-id #'name "opcode:~a" #'name) #'(begin (define op opcode) (struct instr instruction (~? (n ...) ()) #:transparent) (provide op) (provide (struct-out instr)))]) (define-syntax-rule (define-instructions [instrdef ...] ...) (begin (define-instruction instrdef ...) ...)) (define-instructions [#x41 i32.const (n)] [#x42 i64.const (n)] [#x43 f32.const (n)] [#x44 f64.const (n)] [#x0b end]) (define-syntax-parser opcode-case #:literals (else) [(_ e:expr [opcode-name:id rhs ...] ... [else err]) #:with (opcode ...) (for/list ([op (syntax->list #'(opcode-name ...))]) (datum->syntax op (namespace-variable-value (syntax->datum op)))) #'(case e [(opcode) rhs ...] ... [else err])]) but when I use opcode-caselike: (opcode-case x [opcode:i32.const 'i32] [opcode:i64.const 'i64] [opcode:f32.const 'f32] [opcode:f64.const 'f64] [opcode:end 'end] [else 'oops!]) I got: namespace-variable-value: given name is not defined; name: opcode:i32.const I can’t understand why namespace-variable-valuecan’t find opcode:i32.const though it is defined in define-instructions


sorawee
2021-12-15 04:07:40

@mildc055ee You are computing (namespace-variable-value ...) at compile-time, but namespace-variable-value would only be usable at run-time.

Do you really need namespace-variable-value? Can’t you keep the information about opcode at compile-time instead?

(I think there is another issue, which is using a wrong namespace, but I don’t think it’s gonna matter because you should not use namespace-variable-value anyway)


mildc055ee
2021-12-15 06:01:05

@sorawee Ah, I got it. My motivation is that I don’t want to write raw value to case such as: (case op [(#x41) 'i32] [(#x42) 'i64] ... [else 'oops!]) but the code (case op [(opcode:i32.const) 'i32] [(opcode:i64.const) 'i64] ...) and also (match op [opcode:i32.const 'i32] [opcode:i64.const 'i64] ...) does not work because every value are captured by first condition, so I tried macro that rewrites opcode:i32.const to its value.


sorawee
2021-12-15 06:01:56

Try:

#lang racket (require syntax/parse/define (for-syntax racket/syntax syntax/transformer)) (begin-for-syntax (struct opcode (code) #:property prop:procedure (λ (si stx) ((make-variable-like-transformer (datum->syntax stx (opcode-code si))) stx)))) (struct instruction ()) (define-syntax-parser define-instruction [(_ opcode-val:number name:id (~optional (n:id ...))) #:with instr (format-id #'name "instr:~a" #'name) #:with op (format-id #'name "opcode:~a" #'name) #'(begin (define-syntax op (opcode opcode-val)) (struct instr instruction (~? (n ...) ()) #:transparent) (provide op) (provide (struct-out instr)))]) (define-syntax-rule (define-instructions [instrdef ...] ...) (begin (define-instruction instrdef ...) ...)) (define-instructions [#x41 i32.const (n)] [#x42 i64.const (n)] [#x43 f32.const (n)] [#x44 f64.const (n)] [#x0b end]) (define-syntax-parser opcode-case #:literals (else) [(_ e:expr [opcode-name:id rhs ...] ... [else err]) #:with (opcode ...) (for/list ([op (attribute opcode-name)]) (opcode-code (syntax-local-value op))) #'(case e [(opcode) rhs ...] ... [else err])]) (opcode-case #x0b [opcode:i32.const 'i32] [opcode:i64.const 'i64] [opcode:f32.const 'f32] [opcode:f64.const 'f64] [opcode:end 'end] [else 'oops!])


sorawee
2021-12-15 06:05:04

But actually, if it doesn’t need to be super efficient, you can just expand to cond instead of case, where the value is compared sequentially


mildc055ee
2021-12-15 06:20:58

It works, thank you!