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-case
like: (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-value
can’t find opcode:i32.const
though it is defined in define-instructions
…
@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)
@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.
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!])
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
It works, thank you!