countvajhula / countvajhula/cli

Defining macros within a main submodule causes an error

Open
#9 0 comments 0 reactions 0 assignees View on GitHub
bug help wanted
Dominant language
Racket
Stars
15
Forks
0
PR merge metrics
No merged PRs in 30d

Description

## Summary
When using `cli` as the [module language for a `main` submodule](https://docs.racket-lang.org/cli/index.html#%28part._.In_a_main_submodule%29), 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: # 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.

1. 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)
```

2. 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

1. 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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.