Summary
When using cli as the module language for a main submodule, defining a macro within the submodule causes the following error (scroll to the bottom for a workaround):
; /Users/siddhartha/work/lisp/racket/sandbox/cli/bugs/module-macro/bug.rkt:22:5: opt: module mismatch;
; attempted to use a module that is not available
; possible cause:
; using (dynamic-require .... #f)
; but need (dynamic-require .... 0)
; module: #<module-path-index:(submod #<path:/Users/siddhartha/work/lisp/racket/sandbox/cli/bugs/module-macro/bug.rkt> main)>
; phase: 0
; in: opt
; Context (plain; to see better errortrace context, re-run with C-u prefix):
; /Users/siddhartha/.emacs.d/straight/build/racket-mode/racket/syntax.rkt:66:0
; /Users/siddhartha/work/lisp/racket/cli/expander.rkt:146:0 read-spec
; /Users/siddhartha/work/lisp/racket/cli/expander.rkt:181:0 read-specs
; /Users/siddhartha/work/lisp/racket/cli/expander.rkt:207:7 prog
Observations
The error only happens if all of the following are true:
cli is the module language for a main submodule
- at least one flag is defined (via
flag)
- a macro is defined somewhere within the
main submodule
Minimal example
(module* main cli
;; either commenting out this macro, or putting it outside the present
;; module (above it) and then requiring it via (require (submod "..")),
;; causes the problem to disappear
(define-syntax-rule (blah thing)
(thing thing))
;; alternatively, removing this flag causes the
;; problem to disappear as well
(flag (opt name)
("-o" "--option" "An option.")
(opt name))
(program (prog)
(displayln "Hello! The option is:")
(displayln (opt)))
(run prog))
Control examples
These examples are identical in functionality to the example above, but don't exhibit the error.
- Using the
cli as a top level #lang doesn't have this problem:
#lang cli
(define-syntax-rule (blah thing)
(thing thing))
(flag (opt name)
("-o" "--option" "An option.")
(opt name))
(program (prog)
(displayln "Hello! The option is:")
(displayln (opt)))
(run prog)
- For a main submodule using
racket/base as the module language, using parse-command-line directly doesn't have the problem either:
#lang racket/base
(module* main racket/base
(require racket/cmdline)
(define-syntax-rule (blah thing)
(thing thing))
(define opt (make-parameter #f))
(parse-command-line
"prog"
(current-command-line-arguments)
`((once-each
[("-o" "--option")
,(lambda (flg ~opt)
(opt ~opt))
("An option." "option")]))
(λ (flags-accum)
(displayln "Hello! The option is:")
(displayln (opt)))
'()))
Workarounds
- Define the macro outside the main submodule and require it within the main submodule.
It could be defined in the containing module:
(define-syntax-rule (blah thing)
(thing thing))
(provide blah)
(module* main cli
(require (submod ".."))
...)
... or in any other module and just required, as usual:
(module* main cli
(require "macro-containing-module.rkt")
...)
Fix
I haven't had a chance to investigate. The workaround above is reasonably straightforward so it doesn't seem vital to address this bug right away. I would, of course, love for it to be fixed.
Dear Reader: if you're up for a bug hunting challenge, I invite you to take a crack at finding the cause. The above examples show clear cases where it works and doesn't work, and the changes that cause it to go from working to not-working. It's a good start for a seasoned bug hunter like yourself, and could be a fun one to track down. If you decide to try, please share any findings in the comments (or a PR), and your efforts would be greatly appreciated.
If no one gets to it, I'll plan to look at it the next time I'm dedicating time to this package.
Summary
When using
clias the module language for amainsubmodule, defining a macro within the submodule causes the following error (scroll to the bottom for a workaround):Observations
The error only happens if all of the following are true:
cliis the module language for a main submoduleflag)mainsubmoduleMinimal example
Control examples
These examples are identical in functionality to the example above, but don't exhibit the error.
clias a top level#langdoesn't have this problem:racket/baseas the module language, usingparse-command-linedirectly doesn't have the problem either:Workarounds
It could be defined in the containing module:
... or in any other module and just required, as usual:
Fix
I haven't had a chance to investigate. The workaround above is reasonably straightforward so it doesn't seem vital to address this bug right away. I would, of course, love for it to be fixed.
Dear Reader: if you're up for a bug hunting challenge, I invite you to take a crack at finding the cause. The above examples show clear cases where it works and doesn't work, and the changes that cause it to go from working to not-working. It's a good start for a seasoned bug hunter like yourself, and could be a fun one to track down. If you decide to try, please share any findings in the comments (or a PR), and your efforts would be greatly appreciated.
If no one gets to it, I'll plan to look at it the next time I'm dedicating time to this package.