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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//! A parser for g-code programs, with both a convenient AST API and a
//! zero-allocation visitor-based core designed for embedded environments.
//!
//! Some explicit design goals of this crate are:
//!
//! - **embedded-friendly:** users should be able to use this crate without
//! requiring access to an operating system (e.g. `#[no_std]` environments or
//! WebAssembly)
//! - **deterministic memory usage:** the [`crate::core`] parser can operate
//! without dynamic allocation
//! - **error-resistant:** the parser attempts to recover from erroneous input,
//! reporting diagnostics and continuing where possible
//! - **performance:** parsing should be reasonably fast, guaranteeing `O(n)`
//! time complexity with no backtracking
//!
//! # Getting Started
//!
//! With the [`alloc`] feature (enabled by default), use [`parse`] to parse
//! g-code into a [`Program`]. If any parse errors are emitted, [`parse`]
//! returns `Err` with the collected [`Diagnostics`].
//!
//! ```rust
//! # #[cfg(feature = "alloc")]
//! # fn main() -> Result<(), gcode::Diagnostics> {
//! use gcode::{Code, Value};
//!
//! let src = "G90 (absolute)\nG00 X50.0 Y-10";
//! let program = gcode::parse(src)?;
//!
//! assert!(program.blocks.len() >= 1);
//!
//! for block in &program.blocks {
//! for code in &block.codes {
//! if let Code::General(g) = code {
//! for arg in &g.args {
//! match (arg.letter, &arg.value) {
//! ('X', Value::Literal(x)) => assert_eq!(*x, 50.0),
//! ('Y', Value::Literal(y)) => assert_eq!(*y, -10.0),
//! _ => {}
//! }
//! }
//! }
//! }
//! }
//! # Ok(())
//! # }
//! # #[cfg(not(feature = "alloc"))]
//! # fn main() {}
//! ```
//!
//! Parse errors are reported as [`Diagnostic`]s and collected in [`Diagnostics`].
//!
//! For more complex use cases, including zero-allocation or streaming parsing,
//! refer to the [`core`] module.
//!
//! # Document model
//!
//! G-code is modelled as a sequence of *blocks*. A [`Program`] (from [`parse`])
//! is the root: it has `blocks`. Each [`Block`] corresponds roughly to one line
//! of source and contains an optional line number (N), comments, G/M/T
//! commands ([`Code`] with [`Argument`]s), and bare word addresses
//! ([`Block::word_addresses`]—e.g. `X10.5` without a preceding G/M/T).
//!
//! For example, this source:
//!
//! ```text
//! G1 X10.5 Y20.0 F1500
//! M3 S1000
//! ; start cutting
//! ```
//!
//! is a document of three blocks: the first has one G-code (G1) with arguments
//! X, Y, F; the second has one M-code (M3) with S; the third has a comment.
//!
//! Unlike JSON or XML, g-code has no single universal grammar; controllers and
//! dialects differ, and the meaning of a block often depends on machine state
//! or dialect rules. This crate therefore models g-code at the *syntactic*
//! level: the parser represents what was written, not what the machine would
//! do. Higher-level interpretation (e.g. whether X/Y are coordinates for a
//! move) is left to downstream code.
//!
//! # Zero allocation
//!
//! To avoid dynamic allocation, do not enable the `alloc` feature and do not
//! use the [`parse`] function (which builds an AST). Implement
//! [`ProgramVisitor`](crate::core::ProgramVisitor),
//! [`BlockVisitor`](crate::core::BlockVisitor), and
//! [`CommandVisitor`](crate::core::CommandVisitor) and pass your visitor to
//! [`core::parse`]; the parser drives your visitor and does not allocate.
//!
//! # Spans
//!
//! Each element's original location in the source is retained as a
//! [`Span`](crate::core::Span).
//!
//! This supports:
//!
//! - Showing where a parsing or semantic error occurred
//! - Highlighting the current command when stepping through a program
//! - Reporting progress (e.g. line/column) to the user or machine
//!
//! In the core API, visitor methods receive a `Span` (e.g.
//! [`BlockVisitor::line_number`](crate::core::BlockVisitor::line_number) and
//! [`BlockVisitor::comment`](crate::core::BlockVisitor::comment)). AST types
//! (with `alloc`) have a `span` field (e.g. [`Block::span`], [`Comment::span`],
//! [`GeneralCode::span`], [`Argument::span`]).
//!
//! # Feature Flags
//!
// Make sure docs indicate when something is hidden behind a feature flag
extern crate alloc;
pub use crate::;
/// Parse G-code source into a [`Program`] or return [`Diagnostics`] on error.
///
/// Requires the `alloc` feature. For zero-allocation or streaming parsing, use
/// [`core::parse`] with a custom [`ProgramVisitor`](crate::core::ProgramVisitor).