Command Line Interface
This file is part of the Nocter language specification. The specification entry point is README.md.
Direction
Adopted: the nocter command should have a small, stable CLI contract from the beginning.
The CLI must support normal executable generation, lightweight trial execution, editor-oriented checking, source formatting, and an LSP entry point without depending on external assemblers, linkers, SDK tools, or runtime libraries.
Initial commands:
nocter --version
nocter doctor
nocter build
nocter build app.nct
nocter run
nocter run app.nct
nocter app.nct
nocter check
nocter check app.nct
nocter check --format json
nocter check app.nct --format json
nocter fmt app.nct
nocter fmt --check app.nct
nocter tokens app.nct --format json
nocter ast app.nct --format json
nocter lsp
Version
--version prints release identity and exits.
nocter --version
Rules:
--versionis a global option, not a subcommand.--versiondoes not take a root file.--versiondoes not build, run, check, or format source.- Release compiler binaries embed the release version, host, and default target.
- The printed release version must match the
VERSIONandMANIFEST.jsonshipped in the same release archive. - Initial human output should include at least the compiler release, host, and default target.
--versiondoes not emit JSON in v0.
Example output:
Nocter 0.1.0
host: arm64-darwin
default target: arm64-darwin
Doctor
doctor validates the active Nocter home and reports installation problems.
nocter doctor
Rules:
doctordoes not take a root file.doctordoes not build, run, check, format, or execute user code.doctorresolves Nocter home using the rules in Targets and Distribution.doctorchecks thatVERSION,MANIFEST.json, andstd/exist.doctorchecks thatVERSIONmatchesMANIFEST.json'srelease.doctorchecks thatMANIFEST.json.hostmatches the running compiler's host.doctorchecks thatMANIFEST.json.default_targetis listed inMANIFEST.json.implemented_targets.doctorchecks that the commonstd/directory is present.- v1 does not check a compiler binary checksum because
MANIFEST.jsonv1 does not include checksum metadata. - Human-readable output goes to stdout on success and stderr on failure.
doctorexits with status0when the installation is valid.doctorexits with status2for Nocter home, filesystem, manifest, or installation errors.
Root File
build, run, and check take zero or one entry .nct file.
Rules:
- If a file is named on the command line, that file is the entry file.
- If no file is named,
main.nctin the current working directory is the entry file. - The root file must have the
.nctextension. - The source root is the canonical parent directory of the entry file.
- The compiler follows imports from the root file to form the compile unit.
- The compile unit rules are specified in Modules and Use Declarations.
- Package manifests, project-root discovery, workspaces, lockfiles, package registries, separate compilation, and incremental artifacts are not part of v0.
fmt takes one .nct source file but does not treat it as a compile-unit root. It formats only the file named on the command line.
Entry Selection
build, run, shorthand run, and check select the executable entry function.
Default:
nocter run
nocter run app.nct
This selects root-file func main().
Rules:
- The v0 entry function name is fixed to
main. --entryis not part of v0.- Entry lookup considers only top-level functions in the root file.
- Imported functions with the same name are ordinary functions and are not selected as the executable entry.
- The selected function must have no type parameters, no value parameters, and must return
i32!,i32,usize!,usize,void!, orvoid. mainis an ordinary function name except that root-filemainis the v0 executable entry.fmt,tokens, andastdo not perform executable entry validation.
Build
build generates a persistent executable.
nocter build
nocter build app.nct
Rules:
buildruns lexing, parsing, name resolution, type checking, ownership checking, v0 buildability validation, target lowering, ARM64 code generation, and Mach-O executable generation.-o pathsets the executable output path.- If
-ois omitted, the initial driver may derive an output path from the root file stem. buildmust not invokeclang,as,ld, Xcode Command Line Tools, or an external linker.- On success,
buildleaves an executable at the output path. - On failure,
buildmust not leave a partial or corrupt executable at the output path. - The implementation should write to a temporary file in the destination directory and atomically replace the output path only after executable generation succeeds.
Run
run is the lightweight trial execution command.
nocter run
nocter run app.nct
Adopted: run uses a temporary Mach-O executable, not RAM-only execution.
Meaning:
source.nct
-> nocter
-> temporary Mach-O executable
-> spawn / exec
-> remove temporary executable
Rules:
runuses the same front end, semantic checks, v0 buildability validation, target lowering, ARM64 code generation, and Mach-O writer asbuild.rundoes not create a persistent project output file.runcreates a temporary executable in a private temporary location.- The temporary executable is a real Mach-O executable for the active target.
- The temporary executable is removed after the executed program exits.
- If compilation fails, no program is executed.
- If temporary executable creation fails, the command reports a command-line or filesystem error.
- RAM-only execution, JIT execution, and calling the selected entry function inside the compiler process are not part of v0.
runmust not require external tools.runforwards the executed program's standard input, standard output, and standard error by default.
Rationale:
- macOS process execution is path-based for normal executable launch.
- A temporary executable keeps
runbehavior close tobuild. - The compiler validates the same Mach-O path used for persistent executables.
- Process exit, signals, standard streams, working directory, and environment are handled by normal OS process execution instead of an in-process JIT model.
Shorthand Run
The command:
nocter app.nct
is equivalent to:
nocter run app.nct
Rules:
- The shorthand is recognized only when no explicit subcommand is present and the first positional argument is a
.nctroot file. - The shorthand exists for quick local trials.
- Documentation should teach
nocter run app.nctas the explicit form. - Future program arguments for
run, if added, use a--separator to avoid ambiguity with compiler options. - The reserved future shape is
nocter run app.nct -- arg1 arg2. - The shorthand form may mirror that as
nocter app.nct -- arg1 arg2.
Check
check validates a program without emitting or executing an executable.
nocter check
nocter check app.nct
nocter check --format json
nocter check app.nct --format json
Rules:
checkruns lexing, parsing, name resolution, type checking, ownership checking, target selection, and target-gated declaration validation.checkreports the same source-language diagnostics asbuildfor lexing, parsing, import resolution, name resolution, type checking, ownership, target selection, and target-gated declarations.checkdoes not require every accepted construct to be supported by build/run lowering. Constructs explicitly marked check-only in the v0 contract are valid forcheckand are rejected bybuildandrunduring buildability validation.checkdoes not emit an executable.checkdoes not execute user code.--format humanis the default format.--format jsonemits machine-readable diagnostics suitable for editor integrations.- With
--format json, stdout must contain exactly one JSON diagnostic envelope and no other text. - With
--format json, human-readable progress messages must not be printed to stdout. - Human-readable diagnostics are written to stderr.
The JSON diagnostic envelope is specified in Diagnostics.
The root path and source span path rules are specified in Modules and Use Declarations.
Implementation staging:
- Development snapshots may temporarily ship partial
check --format jsoncoverage while the compiler pipeline is being built. - A v0 release
checkimplementation must satisfy the rules above for parsing, import resolution, name resolution, type checking, ownership checking, target selection, target-gated declaration validation, JSON shape, and check-only construct handling.
Format
fmt formats a source file using the official Nocter source style.
nocter fmt app.nct
nocter fmt --check app.nct
Rules:
fmttakes exactly one.nctsource file in v0.fmtformats only the named source file.fmtdoes not follow imports.fmtdoes not perform name resolution, type checking, ownership checking, target lowering, code generation, or execution.fmtparses enough syntax to preserve comments and produce valid Nocter source.- If parsing fails,
fmtreports diagnostics and must not rewrite the file. fmtrewrites the source file in place only after formatting succeeds.fmt --checkreports whether the file already matches formatter output and does not rewrite the file.fmthas no target option.
The formatting rules are specified in Source Style and Formatting.
Tokens
tokens prints the compiler lexer output for one source file.
nocter tokens app.nct --format json
Rules:
tokenstakes exactly one.nctsource file in v0.tokensis JSON-only in v0;--format jsonis required.tokensdoes not follow imports.tokensdoes not parse, resolve names, type-check, ownership-check, target-lower, codegen, emit an executable, or execute user code.tokensuses the same lexer asbuild,run, andcheck.- The JSON output is intended for compiler debugging, editor integration, tests, and AI-assisted code repair.
- The JSON output must include enough source span information to map tokens back to the input file.
The token vocabulary follows Lexical Grammar.
Initial token JSON envelope:
{
"schema": "nocter.tokens",
"version": 1,
"ok": true,
"command": "tokens",
"file": "app.nct",
"absolute_path": "/Users/me/project/app.nct",
"tokens": [
{
"kind": "keyword",
"lexeme": "func",
"span": {
"file": "app.nct",
"absolute_path": "/Users/me/project/app.nct",
"start_byte": 0,
"end_byte": 4,
"start_line": 1,
"start_column_byte": 1,
"end_line": 1,
"end_column_byte": 5
}
}
],
"diagnostics": []
}
Token JSON rules:
schemais"nocter.tokens".versionis1.okistrueonly when lexing succeeded without diagnostics.fileis the input display path.absolute_pathis the canonical absolute path when known, ornull.tokensis an array of token objects.kindis the compiler token kind name.lexemeis the exact normalized source text covered by the token.spanuses the public JSON span shape from Diagnostics.diagnosticsuses the diagnostic object shape from Diagnostics.
AST
ast prints the compiler parser output for one source file.
nocter ast app.nct --format json
Rules:
asttakes exactly one.nctsource file in v0.astis JSON-only in v0;--format jsonis required.astparses one source file and does not follow imports.astdoes not resolve names, type-check, ownership-check, target-lower, codegen, emit an executable, or execute user code.astuses the same lexer and parser asbuild,run, andcheck.- The JSON output is intended for compiler debugging, editor integration, tests, and AI-assisted code repair.
- The JSON output must include source spans for syntax nodes when practical.
- The JSON output may include attached doc comment text for documentable nodes.
- AST JSON is a compiler tooling format, not a stable serialization of the language specification.
The AST command direction is part of Tooling and Editor Integration.
Initial AST JSON envelope:
{
"schema": "nocter.ast",
"version": 1,
"ok": true,
"command": "ast",
"file": "app.nct",
"absolute_path": "/Users/me/project/app.nct",
"ast": {
"kind": "source_file",
"span": {
"file": "app.nct",
"absolute_path": "/Users/me/project/app.nct",
"start_byte": 0,
"end_byte": 34,
"start_line": 1,
"start_column_byte": 1,
"end_line": 3,
"end_column_byte": 2
},
"items": []
},
"diagnostics": []
}
AST JSON rules:
schemais"nocter.ast".versionis1.okistrueonly when parsing succeeded without diagnostics.fileis the input display path.absolute_pathis the canonical absolute path when known, ornull.astis an object when parsing succeeds andnullwhen parsing fails before a useful tree exists.- AST node objects include
kindand should includespanwhen practical. - Expression nodes with source-level operators or operator-like keywords may include
operator_span, such as unary and binary operators, postfix?, postfix!,otherwise,as, andcatch. - AST node objects may include
valuefor compact leaf information such as identifiers, literals, import paths, and type names. - AST node objects may include
documentationwhen adjacent doc comments attach to that node.source_fileusesdocumentationfor//!and/*! ... */. - AST node
spanandoperator_spanfields use the public JSON span shape from Diagnostics. diagnosticsuses the diagnostic object shape from Diagnostics.- AST JSON is allowed to change while the AST is internal and unstable; AI tools should treat it as a tooling aid, not a source compatibility promise.
LSP
lsp starts the language server.
Hover contents use LSP Markdown markup. Item documentation comes from /// and /** ... */; module-path hover documentation comes from the resolved file's //! or /*! ... */ source-file documentation when that module is loaded.
nocter lsp
Rules:
lspdoes not build, run, or check a single root file as a one-shot command.lspspeaks the Language Server Protocol over standard input and standard output.- LSP protocol messages are the only data written to stdout while the server is running.
- Human-readable server logs, if any, must go to stderr or a configured log file.
lspreuses the compiler lexer, parser, resolver, type checker, ownership checker, and diagnostics.- LSP v0 supports
initialize,shutdown,exit, full-documentdidOpen/didChange/didClose,textDocument/publishDiagnostics,textDocument/documentSymbol,textDocument/definition,textDocument/references,textDocument/hover,textDocument/completion, andtextDocument/semanticTokens/full. - During
initialize, LSP v0 recordsworkspaceFolderswhen present and falls back torootUriwhen no workspace folders are provided. - LSP v0 advertises UTF-16 positions and converts compiler-owned UTF-8 byte spans before publishing diagnostics, hover ranges, definition locations, document symbol ranges, and semantic tokens.
- LSP v0 treats
didChangeas full-document sync. If both the stored document and incoming change have versions, an incoming version older than the stored version is ignored. - LSP v0 uses the current text of open documents when resolving imports in a compile unit, so diagnostics, hover, definition, references, completion, and semantic tokens can reflect unsaved imported files that are part of the opened compile unit.
- LSP v0 clears diagnostics for documents that were previously published but are no longer part of the latest diagnostic publish set.
- LSP v0 records workspace roots for later project-level behavior, but compile-unit analysis is still driven by the opened root document being diagnosed.
- LSP v0 returns Markdown hover contents from compiler-owned semantic data and documentation comments.
- LSP v0 returns go-to-definition locations for local references, top-level declarations, loaded imported declarations, loaded import module paths, fields, enum variants, associated functions, and method calls covered by compiler analysis.
- LSP v0 returns references for local symbols, top-level declarations, loaded imported declarations, type references, fields, enum variants, associated functions, and method calls covered by compiler analysis.
- LSP v0 returns document symbols for top-level declarations and nested struct fields or enum variants represented by the parser.
- LSP v0 returns basic completion items for keywords and visible resolved symbols. Import-path segment completion and context-sensitive member completion are deferred.
- LSP v0 returns full semantic tokens for compiler-classified functions, methods, variables, parameters, types, and properties.
- After
shutdown, LSP v0 ignores notifications other thanexitand returns a JSON-RPC invalid-request error for ordinary requests.exitaftershutdownexits successfully;exitbeforeshutdownexits with status1. - LSP v0 does not provide rename, formatting requests, workspace-wide indexing, context-sensitive member completion, or incremental parsing.
The editor integration direction is specified in Tooling and Editor Integration.
Target Option
build, run, and check accept an optional target:
nocter build app.nct -o app --target arm64-darwin
nocter run app.nct --target arm64-darwin
nocter check app.nct --target arm64-darwin
Rules:
- If
--targetis omitted, the compiler uses the host target. - The initial implemented target is
arm64-darwin. - Reserved future target names may be recognized before implementation.
- Requesting a recognized but unimplemented target is a target-selection error.
runcan execute only targets that are runnable on the current host.- In v0, practical
runsupport is limited toarm64-darwinon an ARM64 macOS host. fmtdoes not accept--targetbecause source style is target-independent.tokensandastdo not accept--targetbecause lexing and parsing are target-independent.
Output Streams
Rules:
- Human-readable diagnostics go to stderr.
- Human-readable command-line and filesystem errors go to stderr.
--versionwrites version information to stdout.doctorwrites a success summary to stdout and failure details to stderr.buildshould not print normal success output unless requested by a future verbosity option.runforwards the child program's stdout and stderr by default.check --format jsonwrites exactly one JSON diagnostic envelope to stdout and no non-JSON text to stdout.fmt --checkmay print human-readable formatting differences or a summary to stderr.tokens --format jsonwrites exactly one JSON token envelope to stdout and no non-JSON text to stdout.ast --format jsonwrites exactly one JSON AST envelope to stdout and no non-JSON text to stdout.lspreserves stdout for LSP protocol messages.
Exit Status
Compiler-owned exit statuses:
0 success
1 source diagnostics or `fmt --check` formatting difference
2 command-line, filesystem, Nocter home, target-selection, or temporary executable error
3 internal compiler error
Rules:
buildandcheckuse compiler-owned exit statuses.--versionuses compiler-owned exit statuses.doctoruses compiler-owned exit statuses.fmtuses compiler-owned exit statuses.fmt --checkexits with status1when the file would be changed by formatter output.lspuses compiler-owned exit statuses when startup fails.- After
runsuccessfully starts the compiled program, thenocter runprocess exits with the executed program's exit status. - If
runfails before starting the program, it uses compiler-owned exit statuses. - If the executed program terminates by signal,
runfollows the host platform's conventional process-status reporting.
Not Adopted in v0
The following are not part of v0:
- RAM-only execution
- JIT execution
- in-process execution of the selected Nocter entry function
- external assembler or linker fallback
- project-wide formatting
- package manifest commands
- package registry commands
- project-wide command configuration
- passing
runchild-process arguments before the--forwarding design is implemented - entry function type parameters such as
func main<T>(): i32! - entry function value parameters such as
func main(args: Vec<&str>): i32!