Expand description
A crate for parsing g-code programs, designed with embedded environments in mind.
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 library can be tweaked to use no
dynamic allocation (see the
crate::coremodule) - error-resistant: erroneous input won’t abort parsing, instead
notifying the caller and continuing on (see
crate::core::Diagnostics) - performance: parsing should be reasonably fast, guaranteeing
O(n)time complexity with no backtracking
§Getting Started
§Simple parsing (with alloc)
With the alloc feature (enabled by default), use parse to get a
Program and any Diagnostics. You can then walk Blocks and
inspect Codes (e.g. Code::General) and their Arguments.
use gcode::ast::{Code, Value};
let src = "G90 (absolute)\nG00 X50.0 Y-10";
let result = gcode::parse(src)?;
let program = result;
assert!(program.blocks.len() >= 1);
for block in &program.blocks {
for code in &block.codes {
if let Code::General(g) = code {
let args: HashMap<char, _> = g.args.iter()
.map(|a| (a.letter, a.value.clone()))
.collect();
let Some(x) = args.get(&'X') else { continue; };
let Some(y) = args.get(&'Y') else { continue; };
assert_eq!(x, &Value::Literal(50.0));
assert_eq!(y, &Value::Literal(-10.0));
}
}
}Parse errors are collected as Diagnostics. The parse function fails
if any parse errors were emitted.
§Push-based / zero-allocation parsing
The core module is designed guaranteed to parse without requiring any
heap allocations.
Implement
ProgramVisitor: the parser calls
ProgramVisitor::start_block and
you return a ControlFlow::Continue with a
BlockVisitor. That visitor receives
BlockVisitor::line_number,
BlockVisitor::comment, and
BlockVisitor::start_general_code
(and similar for M/O/T), returning a
CommandVisitor for each command. See
crate::core for the full visitor model and resume
for pause/resume.
use gcode::core::{
BlockVisitor, CommandVisitor, ControlFlow, Noop, ProgramVisitor,
};
let src = "G90 G01 X5";
gcode::core::parse(src, &mut Noop);§Zero allocation
To avoid dynamic allocation, do not enable the alloc feature and do not
use the parse function (which builds an AST). Implement the
ProgramVisitor,
BlockVisitor, and
CommandVisitor traits 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.
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 and
BlockVisitor::comment). AST types
(with alloc) have a span field (e.g. Block::span, Comment::span,
GeneralCode::span, Argument::span).
§Feature Flags
alloc(enabled by default) — Enables theastmodule andparse, producing aProgramand collectingDiagnostics.serde(enabled by default) — Enables serialisation and deserialisation of core and AST types viaserde.
§Internal Features
The following features are not intended for public use.
unstable-doc-cfg— Enables rustdoc labels for items gated by features (for docs.rs - requires nightly).
Re-exports§
pub use crate::ast::parse;alloc