Egglog AST macros with unquote and unquote splice#947
Draft
oflatt wants to merge 10 commits into
Draft
Conversation
9848a4d to
e11bc66
Compare
Token-tree quasiquotes that route egglog written as Rust tokens through the parser: `expr!`, `fact!`, `facts!`, `action!`, `actions!`, `command!`, `egglog!`, `rule!`, `sexp!`, `sexps!`. Adds: - the `egglog-quote` proc-macro crate, - `parse.rs` helpers: `atom_to_sexp`, `keyword_to_sexp`, the `ToSexp` trait (+ impls for Sexp/&str/String/i64/Expr), `expr_to_sexp`, and an iterative `Display for Sexp` (heap work-stack, so deep list chains can't overflow), - re-exports from the crate root and `prelude`. The proc-macros replace the old infallible `macro_rules!` `expr!`/`fact!`/ `facts!`/`action!`/`actions!`: they now go through the parser (so `?x`, `:field`, `...`, `#`-splices, and every registered parser macro work) and return `Result`. Ported the call sites in tests/benches accordingly. Upstream's `query`/`rule`/`rust_rule` API is kept; `rule!` is reachable as `egglog::rule!` but not re-exported into `prelude` (it would collide with the `rule()` helper fn). `#(expr)` splices unwrap the parens so the generated `to_sexp(expr, ..)` is `unused_parens`-clean under `-D warnings`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add a "Writing egglog inline from Rust" section (with a runnable, tested example) to the crate-root docs (lib.md). - Fix pre-existing broken intra-doc links in proofs::proof_format: the private `RawProof`/`RawProof::Rule` links become code spans, `Fact` points at `crate::ast::Fact`, and the `Propostion` typo is fixed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #947 +/- ##
==========================================
- Coverage 86.42% 86.13% -0.29%
==========================================
Files 94 97 +3
Lines 29102 29759 +657
==========================================
+ Hits 25151 25634 +483
- Misses 3951 4125 +174 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
e11bc66 to
fda2a26
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
Give every parsing quasiquote three flavors: - `x!` — parse only (optional parser) -> unresolved AST - `resolve_x!(eg, …)` — typecheck against the e-graph -> Resolved… (no run) - `run_x!(eg, …)` — resolve + execute -> execution result Covers expression / query / action(s) / command / program (egglog) / rule. Returns: `run_egglog!`/`run_command!`/`run_rule!`/`run_action(s)!` -> `Vec<CommandOutput>`; `run_expr!` -> `(ArcSort, Value)`; `run_query!` -> `Vec<HashMap<String, Value>>` (matches, with vars derived from the facts so no explicit `vars` needed). `resolve_*` return the matching `Resolved…` AST. Naming: since each variant has a distinct name, no parser-vs-e-graph type dispatch is needed. `run_` returns the *execution result*, not the resolved AST, so `run` and `resolve` stay distinct. Hard-renamed `facts!` -> `query!` (and dropped the singular `fact!`): "running facts" is a query, so `run_query!` returning matches is the natural fit. Supporting e-graph methods (thin wrappers over existing internals): `resolve_commands`, `resolve_expr`, `resolve_facts`, `query_all`. Also derived `Clone` for `Sexp` (needed to build `(rule …)` from spliced parts). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Drop the "no quotes" / "real parser" framing (it implied an alternative the
reader has no context for); describe the macros in their own terms.
- Trim the lib.md section to a short intro + a small runnable example, and
point to the `egglog_quote` crate for the full reference.
- Soften jargon ("round-trip" / "splices as identity") in the parse.rs and
sexp! docs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`rule(egraph, ruleset, facts, actions)` is subsumed by `run_egglog!(egraph, (rule (<facts>) (<actions>) :ruleset r))` (and `run_rule!` for the default ruleset) now that the run macros exist — it had no library callers, only tests/doctests. Removing it also frees the name: `rule!` is now re-exported into `prelude` alongside `resolve_rule!`/`run_rule!` (it was held out only to avoid colliding with the fn), so the rule triple is complete and consistent with the other categories. Migrated the test/doc call sites to `run_egglog!((rule … :ruleset …))`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Remove `add_sort` / `add_function` / `add_constructor` / `add_relation`: 0 callers, and each is just `run_egglog!(eg, (sort …))` / `(function …)` / `(constructor …)` / `(relation …)` with a `Schema` struct instead of egglog syntax. (Two were only ever used by the removed `datatype!`.) - `add_base_sort` / `add_container_sort` register a Rust sort *type* (no egglog text equivalent), so they stay — but drop their redundant explicit `span: Span` parameter (every caller passed `span!()`) and use `span!()` internally, matching how the rest of the API hides spans. The remaining Rust-side helpers already fit the new API: `rust_rule` / `rust_rule_full` / `EGraph::query` take `Facts` (what `query!` produces); `add_ruleset` / `run_ruleset` are thin typed conveniences used internally by `query`/`rust_rule`; `exprs` / `sort!` / `vars!` are the low-level builders that back `rust_rule`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Put the full, user-facing macro guide — the parse / resolve_* / run_* table,
the splice forms, and an example — in `egglog::prelude`, alongside the rest of
the Rust API (custom rules, primitives, sorts). It leads the module now, since
writing egglog inline is the primary way to use egglog from Rust.
- `egglog-quote`'s module doc shrinks to a one-line pointer (it's an
implementation crate; users read `egglog::prelude`).
- `lib.md` keeps a short intro + example and points at [`prelude`].
- Per-macro docs point to `egglog::prelude` instead of "the module docs".
- Dropped implementation framing ("token-tree", "routes through the parser",
`ToSexp`/`Sexp` internals) in favor of what the macros let you do.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
egglog_header! now also generates `pub fn <name>_schema() -> Result<Vec<Command>, egglog::Error>` returning the header's declarations as commands. A schema can then be declared once (the header) and used for BOTH compile-time checking (the generated macro) and runtime emission (the fn), instead of being restated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.