Skip to content

feat(cli): call namespace entry points with -m - #1097

Closed
mparrett wants to merge 3 commits into
nooga:mainfrom
mparrett:codex/cli-main-1096
Closed

mparrett wants to merge 3 commits into
nooga:mainfrom
mparrett:codex/cli-main-1096

Conversation

@mparrett

Copy link
Copy Markdown
Collaborator

Fixes #1096.

lg can load a namespace's source file but has no CLI entry point for calling its -main. Programs currently need a launcher script or a manual -e call, which also prints the return value and treats the first program argument as a script.

Adds lg [-source-paths …] -m ns [args…] and --main. The namespace is required through the existing loader, all remaining arguments are bound to *command-line-args* before initialization/loading and passed as strings to ns/-main, and the return value is discarded. Loading and invocation failures exit nonzero.

Design choices:

  • -m ns/fn selects another callable var.
  • -m is terminal: even flag-shaped arguments and a literal -- after the target belong to the program. Other options must precede it.
  • -e runs before requiring/calling the target, with the arguments already available; its result still prints as usual. An initialization error prevents the entry call. Existing script-plus--e ordering stays unchanged.
  • -r retains the existing post-execution REPL behavior. Combining -m with -c, -b, or -w is a usage error.

The CLI reuses rt.RequireNS and rt.InvokeProgramEntry. No compiler, IR, AOT, or generated runtime changes are needed; the default and bootstrap builds exercise the same entry path, and an *ir-compile* initialization probe also passes.

Validation:

  • make build (including correctness and boot smoke): passed.
  • make test: passed (uninitialized Clojure test-suite submodule and normal short-mode skips).
  • go test ./test/e2e -run 'TestMainFlag|TestCommandLineArgs' -count=1 -v: passed; 20 new CLI cases plus existing script/bundle argument coverage.
  • go test -tags bootstrap ./test/e2e -run TestMainFlag -count=1: passed.
  • go test -short ./pkg/cli/... and go vet ./pkg/cli/...: passed, including 11 parser cases covering custom host flags, positional scripts, terminators, and malformed flags.
  • Full pre-push Go tests, benchmark performance ratchet, lowering-coverage ratchet, generated-artifact manifest freshness, and compiled-binary guard: passed.
  • Documentation frontmatter, test locations, formatting, diff whitespace, and scoped comment report: passed (comment report flags only an unchanged existing block).

Local lint limitation: both make lint-go and the pinned pre-commit linter stop in typechecking before analyzing the changes because their importer supports Go export-data version 4 while local Go 1.27.3 emits version 5 (internal/goarch). Only that pre-commit hook was skipped; the remaining commit hooks passed.

mparrett and others added 3 commits October 24, 2026 10:41
With -m there is no script argument, so the storage id fell through to the
executable's basename: every -m program shared the "lg" store with the REPL,
and a program launched as `lg app.lg` lost its data when launched as
`lg -m app`. Derive the id from the namespace's file path instead, so
`lg -m app.core` uses the same store as `lg src/app/core.lg`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
runNamespaceMain passed rt.InvokeProgramEntry's errors through, so users saw
"InvokeProgramEntry: app/-main not found". Look up and check the entry
in the namespace RequireNS returns and report "-m: app/-main not found".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLI: add -m ns to call a namespace's -main, as clojure -m and bb -m do

1 participant