(zilch lang rust): document

Change-Id: I6a6a6964c8aaff8d5f3e18bc5c7486746b5a2952
This commit is contained in:
puck 2025-06-23 12:22:20 +00:00
parent ae774da043
commit 0340f6e830
10 changed files with 597 additions and 82 deletions

View file

@ -1,3 +1,4 @@
;; Procedures to parse Cargo files.
(define-library (zilch lang rust cargo)
(import
(scheme base) (scheme write) (scheme process-context) (scheme lazy)
@ -13,21 +14,6 @@
(zilch vfs))
(export
<cargo-target> make-cargo-target cargo-target?
cargo-target-name cargo-target-path cargo-target-test cargo-target-doctest
cargo-target-bench cargo-target-doc cargo-target-proc-macro cargo-target-harness
cargo-target-edition cargo-target-crate-type cargo-target-required-features
<cargo-dep-git> make-cargo-dep-git cargo-dep-git?
cargo-dep-git-url cargo-dep-git-rev-type cargo-dep-git-rev
<cargo-dep-path> make-cargo-dep-path cargo-dep-path? cargo-dep-path-path
<cargo-dep-registry> make-cargo-dep-registry cargo-dep-registry? cargo-dep-registry-name
<cargo-dependency> make-cargo-dependency cargo-dependency?
cargo-dependency-name cargo-dependency-origin cargo-dependency-version
cargo-dependency-default-features cargo-dependency-features cargo-dependency-package
cargo-dependency-optional
<cargo-crate> make-cargo-crate cargo-crate?
cargo-crate-name cargo-crate-version cargo-crate-edition cargo-crate-dependencies
cargo-crate-features cargo-crate-lib-target cargo-crate-targets
@ -38,6 +24,21 @@
cargo-workspace-members cargo-workspace-exclude cargo-workspace-dependencies
cargo-workspace-version cargo-workspace-edition
<cargo-dependency> make-cargo-dependency cargo-dependency?
cargo-dependency-name cargo-dependency-origin cargo-dependency-version
cargo-dependency-default-features cargo-dependency-features cargo-dependency-package
cargo-dependency-optional
<cargo-dep-git> make-cargo-dep-git cargo-dep-git?
cargo-dep-git-url cargo-dep-git-rev-type cargo-dep-git-rev
<cargo-dep-path> make-cargo-dep-path cargo-dep-path? cargo-dep-path-path
<cargo-dep-registry> make-cargo-dep-registry cargo-dep-registry? cargo-dep-registry-name
<cargo-target> make-cargo-target cargo-target?
cargo-target-name cargo-target-path cargo-target-test cargo-target-doctest
cargo-target-bench cargo-target-doc cargo-target-proc-macro cargo-target-harness
cargo-target-edition cargo-target-crate-type cargo-target-required-features
cfg-values
parse-cargo-toml)
@ -56,7 +57,22 @@
; (define-values (_ _ _) (process-wait pid))
parsed)
;; dependencies here is a list of (name . version-or-#f). if #f, use any version (should be unambiguous!)
;; A single target for a crate.
;;
;; Each crate consists of multiple targets; e.g. `lib`, ``bin``s, and things like test/doctest.
;;
;; The fields of this record closely match the Cargo.toml. For more information on these, see https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target:[the Cargo documentation].
;;
;; - `name`: The name of this target. By default, the name of the binary or
;; of the crate, if lib.
;; - `path`: The root source file for this target (e.g. `"src/lib.rs"`, `"src/bin/example.rs"`).
;; Relative to the crate's root.
;; - `crate-type`: The type of crate, as a symbol (bin, lib, rlib, etc).
;; - `edition`: The target's edition
;; - `required-features`: A specifying which features on the `lib` have to be set.
;; (non-lib targets implicitly depend on the lib target)
;;
;; Based on the `crate-type` the other fields may be valid; these closely match the `Cargo.toml`'s definitions as well.
(define-record-type <cargo-target>
(make-cargo-target name path test doctest bench doc proc-macro harness edition crate-type required-features)
cargo-target?
@ -71,7 +87,7 @@
(edition cargo-target-edition) ; defaults to package's edition field
(crate-type cargo-target-crate-type) ; [bin, lib, rlib, dylib, cdylib, staticlib, proc-macro]
(required-features cargo-target-required-features)) ; list. has no effect on lib
(define-record-printer (<cargo-target> entry out)
(fprintf out "#<cargo-target ~S ~S test:~S doctest:~S bench:~S doc:~S proc-macro:~S harness:~S edition:~S ~S required-features:~S>"
(cargo-target-name entry)
@ -85,7 +101,7 @@
(cargo-target-edition entry)
(cargo-target-crate-type entry)
(cargo-target-required-features entry)))
; either:
; - git + optionally tag/rev/branch (this supports looking at workspace.toml, as an exception)
; - path (relative)
@ -98,7 +114,10 @@
; - package (used for resolving against the registry)
; - optional (only if feature is enabled!)
; or like, workspace (+ optional/features, whee)
;; A Git cargo dependency.
;; `rev-type` is either `'tag`, `'rev`, `'branch`, or `#f`, and specifies
;; how `rev` is interpreted.
(define-record-type <cargo-dep-git>
(make-cargo-dep-git url rev-type rev)
cargo-dep-git?
@ -111,7 +130,9 @@
(cargo-dep-git-url entry)
(cargo-dep-git-rev-type entry)
(cargo-dep-git-rev entry)))
;; A path cargo dependency.
;; The path is relative to the crate root.
(define-record-type <cargo-dep-path>
(make-cargo-dep-path path)
cargo-dep-path?
@ -120,7 +141,8 @@
(define-record-printer (<cargo-dep-path> entry out)
(fprintf out "#<cargo-dep-path ~S>"
(cargo-dep-path-path entry)))
;; A registry dependency.
(define-record-type <cargo-dep-registry>
(make-cargo-dep-registry name)
cargo-dep-registry?
@ -129,6 +151,17 @@
(fprintf out "#<cargo-dep-registry ~S>"
(cargo-dep-registry-name entry)))
;; A crate's dependency.
;;
;; - `name`: the name this dependency has in the Rust code.
;; - `origin`: a `<cargo-dep-git>`, `<cargo-dep-path>`, or
;; `<cargo-dep-registry>`, specifying the source of the dependency.
;; - `version`: The version requirements, as a string. Optional for
;; non-registry depndencies.
;; - `default-features`: Whether default features are requested on this dependency.
;; - `features`: A list of features requested.
;; - `package`: The name of the crate being depended upon.
;; - `optional`: Whether this dependency is optional.
(define-record-type <cargo-dependency>
(make-cargo-dependency name origin version default-features features package optional)
cargo-dependency?
@ -148,7 +181,39 @@
(cargo-dependency-features entry)
(cargo-dependency-package entry)
(cargo-dependency-optional entry)))
;; A representation of a Cargo crate.
;;
;; - `name`: The name of the crate
;; - `version`: The version of the crate
;; - `edition`: The edition of Rust this crate uses. Can be overridden by
;; individual targets.
;; - `workspace`: A reference to the workspace this crate is part of, or
;; `#f` if none.
;; - `dependencies`: A list of `<cargo-dependency>` records.
;; - `build-dependencies`: A list of `<cargo-dependency>` records, used for
;; the `build-script` only.
;; - `features`: An alist of feature names to any features it depends on.
;; A feature dependency is represented as a triple `((crate-name . activates-crate) . crate-feature)`.
;; `crate-name` and `activates-crate` govern the target crate. If
;; `crate-name` is `#f`, the feature depends on another feature in the
;; same crate. `activates-crate` specifies whether this is a required
;; dependency, or whether the feature should be enabled when another
;; feature requires the crate. `crate-feature` specifies the name of the
;; feature in the target crate, or `#f` if this feature only depends on
;; the crate itself. As examples:
;; +
;; ** "dep:foo" resolves to (("foo" . #t) . #f)
;; ** "foo/bar" resolves to (("foo" . #t) . "bar")
;; ** "foo?/bar" resolves to (("foo" . #f) . "bar")
;;
;; - `lib-target`: the `<cargo-target>` of the library of the crate, or `#f` if this crate
;; has no library.
;; - `build-script`: the `<cargo-target>` of the build script, if any is present.
;; - `links`: the name of a native library being linked to, or `#f` if none.
;; - `check-cfg-lint`: A list of `--check-cfg` flags to be set on compiling
;; this crate. These values are sourced from `lints.rust.unexpected_cfgs`
;; in the `Cargo.toml`.
(define-record-type <cargo-crate>
(make-cargo-crate name version edition workspace dependencies build-dependencies features lib-target build-script targets links check-cfg-lint)
cargo-crate?
@ -175,6 +240,15 @@
(cargo-crate-lib-target entry)
(cargo-crate-targets entry)))
;; A representation of a Cargo.toml's workspace.
;;
;; - `members`: A list of members of this workspace.
;; - `exclude`: A list of globs that should be excluded, even when mentioned
;; in `members`.
;; - `dependencies`: A list of ``<cargo-dependency>``s that any crate part
;; of this workspace can reference.
;; - `edition`, `version`, `check-cfg-lint`: Default values for the
;; equivalent fields in this workspace's ``<cargo-crate>``s.
(define-record-type <cargo-workspace>
(make-cargo-workspace members exclude dependencies edition version check-cfg-lint)
cargo-workspace?
@ -190,7 +264,7 @@
(cargo-workspace-members entry)
(cargo-workspace-exclude entry)
(cargo-workspace-dependencies entry)))
(foreign-declare "#include \"cfgfetch_source.h\"")
(define cfgfetch-bin
(cdar
@ -210,6 +284,8 @@
(let* ((line (cfg-parse line)))
(read-cfg-value port (cons (cdr line) rest)))))
;; The list of config values that `rustc` sets by default, processed by xref:zilch.lang.rust.cfg.adoc#cfg-parse[`cfg-parse`].
;; These are used to parse `Cargo.toml` conditional dependencies.
(define cfg-values
(let ((vals (cdar (store-path-for-ca-drv* "cfg-values" "x86_64-linux" #~(#$cfgfetch-bin) #~(("rustc" . ,(string-append #$rustc "/bin/rustc"))) '("out")))))
(call-with-port (store-path-open vals) (lambda (p) (read-cfg-value p '())))))
@ -224,7 +300,7 @@
(define (and-cdr-default val default)
(if val (cdr val) default))
(define (find-dependency-in-list l dep-name)
(cond
((null? l) #f)
@ -238,12 +314,12 @@
(define pkg-features (and-cdr-default (assoc "features" object-internals) '()))
(define package (or (and-cdr (assoc "package" object-internals)) name))
(define optional (and-cdr (assoc "optional" object-internals)))
(define git-url (and-cdr (assoc "git" object-internals)))
(define git-tag (and-cdr (assoc "tag" object-internals)))
(define git-rev (and-cdr (assoc "rev" object-internals)))
(define git-branch (and-cdr (assoc "branch" object-internals)))
(define registry-name (and-cdr (assoc "registry" object-internals)))
(define path (and-cdr (assoc "path" object-internals)))
@ -310,7 +386,7 @@
(define required-features (or (and-cdr (assoc "required-features" object-internals)) '()))
(make-cargo-target name path test doctest bench doc proc-macro harness edition crate-type required-features))
; A feature is two parts: ((crate-name . activates-crate) package-feature)
; "dep:foo" resolves to (("foo" . #t) . #f)
; "foo/bar" resolves to (("foo" . #t) . "bar")
@ -343,7 +419,7 @@
(unless vfs (error "no vfs"))
(define package (vector->list (cdr (assoc "package" internals))))
(define package-name (cdr (assoc "name" package)))
(define package-version (cdr (assoc "version" package)))
(define package-version (or (and-cdr (assoc "version" package)) "0.0.0"))
(define package-links (and-cdr (assoc "links" package)))
(define package-edition (or (and-cdr (assoc "edition" package)) "2015"))
@ -363,7 +439,7 @@
(define lib-target #f)
(when (or (assoc "lib" internals) (vfs-file-ref vfs "src" "lib.rs"))
(set! lib-target (cargo-target-from-toml vfs (or (and-cdr (assoc "lib" internals)) #()) package-name 'lib package-edition)))
(define other-targets '())
(cond
((assoc "bin" internals)
@ -445,6 +521,14 @@
(set-cargo-workspace-dependencies! workspace-record dependencies)
workspace-record)
;; Parse the contents of a `Cargo.toml`. Returns two values: A `<cargo-crate>`
;; representing the crate (or `#f` if this is purely a workspace), and a
;; `<cargo-workspace>` the `Cargo.toml` defined (or the workspace passed in,
;; if any).
;;
;; - `vfs`: The VFS to use to automatically detect `bin` and `lib` targets.
;; - `cargo-file`: A string representing the contents of the `Cargo.toml` to use.
;; - `workspace`: A workspace that this rcate is part of, or `#f` if none.
(define (parse-cargo-toml vfs cargo-file workspace)
(define internals (vector->list (parse-toml cargo-file)))
(define crate #f)