1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! plan9 mk build-tool core library.
//!
//! mk-core is a faithful Rust port of Andrew Hume's Plan 9 `mk`. It reads mkfiles,
//! builds a dependency graph, resolves pattern-based metarules, and dispatches
//! parallel recipe execution through a shell abstraction.
//!
//! # Pipeline
//!
//! Each `build()` call runs these stages in sequence, each producing an owned
//! output consumed by the next:
//!
//! ```text
//! ┌─────────────────────────────┐
//! │ mkfile(s) │ user-authored text
//! └──────────────┬──────────────┘
//! │
//! ┌──────────────▼──────────────┐
//! │ lex::Lexer │ char-by-char → token stream
//! └──────────────┬──────────────┘
//! │ TokenStream
//! ┌──────────────▼───────────────────────────┐
//! │ parse::parse_with_scope(tokens, &mut │ recursive descent → AST with
//! │ Scope) │ rule-header vars + assignment
//! │ │ RHS expanded at read-time (F-045)
//! └──────────────┬───────────────────────────┘
//! │ Vec<Stmt> (headers/RHS already expanded;
//! │ recipe bodies still literal, expanded at exec time)
//! ┌──────────────▼───────────────────────────┐
//! │ graph::build_graph(stmts, targets) │ AST → DAG (metarules, transitive
//! │ │ closure, pruning, cycle detection)
//! └──────────────┬───────────────────────────┘
//! │ Graph
//! ┌──────────────▼───────────────────────────┐
//! │ graph::stale_nodes(&graph) │ mtime staleness; virtual targets
//! │ │ unconditionally stale (no file)
//! └──────────────┬───────────────────────────┘
//! │ stale NodeIndex set
//! ┌──────────────▼───────────────────────────┐
//! │ sched::Engine │ parallel DAG walk, NPROC pool,
//! │ │ keep-going (-k), exclusive (E)
//! └──────────────┬───────────────────────────┘
//! │ Job queue
//! ┌──────────────▼───────────────────────────┐
//! │ recipe::run() │ feed recipe to shell; inject
//! │ │ $target/$prereq/$stem env vars
//! └──────────────┬───────────────────────────┘
//! │ exit code
//! ┌──────────────▼───────────────────────────┐
//! │ BuildOutcome │ success, partial (-k), or failure
//! └──────────────────────────────────────────┘
//! ```
//!
//! Variable expansion is split across two stages: rule headers and assignment
//! RHS are expanded at parse-time via the threaded `Scope` (F-045); recipe
//! bodies are kept literal and `$target`/`$prereq`/`$stem` are injected as
//! environment variables just before shell dispatch.
//!
//! # Module roster
//!
//! | Module | Purpose |
//! |--------|---------|
//! | [`lex`] | Tokenizer — comment stripping, line continuation, backtick regions, quoting |
//! | [`parse`] | Recursive-descent parser — rules, assignments, includes, attributes |
//! | [`graph`] | DAG builder — metarule application, transitive closure, cycle/staleness checks |
//! | [`var`] | Variable system — symbol table, `$VAR`/`${VAR}` expansion, namelists |
//! | [`shell`] | `Shell` trait — abstraction for recipe execution (implementations in mk-shell) |
//! | [`recipe`] | Recipe glue — env injection, attribute handling, CLI flag dispatch |
//! | [`sched`] | Scheduler — parallel DAG traversal, NPROC worker pool, keep-going support |
//! | [`attr`] | Attribute bitflags — `V`/`Q`/`N`/`U`/`D`/`E`/`P`/`R`/`n` |
//! | [`mod@include`] | Recursive `< file` includes — child scopes, circular detection |
//! | [`archive`] | `lib(member)` syntax — archive member auto-rule generation |
//! | [`error`] | Centralized error types — `MkError`, `LexError`, `ParseError`, … |