Build grammar expressions directly in a shared finite-state machine - #727
Merged
Merged
Conversation
Add behavior tests for sequence FSM construction: exhaustive comparisons against reference regexes, UTF-8 byte strings, long mixed sequences, recursive rule references, large repetition ranges, token edges, and bitmask consistency with string acceptance.
This was referenced Jul 27, 2026
Stream sequence and choice fragments into one target FSM so element builders can reuse caller-provided start states without temporary FSM copies.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR refactors FSM construction during grammar compilation to stream sequence elements and choice branches directly into a single target FSM, reducing intermediate FSM allocations/copies and improving compile-time performance while preserving resulting FSM structure.
Changes:
- Refactor C++ FSM builder to build sequences/choices by appending directly into a caller-owned target FSM and returning end-state ID sets.
- Update character-class range building helpers to operate directly on
FSM(instead ofFSMWithStartEnd) to support in-place construction. - Add a new Python correctness test suite covering sequence construction across element types, recursion, UTF-8, and token/bitmask behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| tests/python/test_fsm_sequence_build.py | Adds extensive correctness coverage for streamed sequence/choice FSM construction and token-bitmask behavior. |
| cpp/grammar_functor.cc | Refactors sequence/choices FSM building to stream into a shared target FSM; adapts character-range helpers for in-place FSM mutation. |
Comments suppressed due to low confidence (1)
tests/python/test_fsm_sequence_build.py:98
- The return type annotation
-> (str, str)is not a valid typing return type for mypy (it’s a runtime tuple value). Since the project supports Python 3.8 and uses mypy strict, preferTuple[str, str].
def _build_long_sequence_grammar(num_segments: int) -> (str, str):
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import itertools | ||
| import re | ||
| import sys | ||
| from typing import List |
Require fragment builders to hold a valid target FSM and centralize per-rule dispatch, while preserving existing standalone builder entry points. Add golden structure checks that detect any change in state numbering, edge order, or complete-FSM layout.
Regenerate the JSON-pattern case with the explicit main native library so the golden digest tracks the intended baseline rather than an installed package.
Build rule state machines recursively so construction no longer depends on the normalized choice-sequence-element layout.
Ubospica
force-pushed
the
perf/fsm-sequence-build
branch
2 times, most recently
from
July 28, 2026 13:35
d8a264f to
23746d7
Compare
This was referenced Jul 28, 2026
Ubospica
added a commit
that referenced
this pull request
Jul 28, 2026
## Summary - consolidate the 14 EBNF exact-layout cases into the FSM sequence-builder test suite added by #727 - remove two JSON Schema snapshots and one structural-tag snapshot whose layouts change with unrelated converter implementations - fix the long-sequence helper's Python 3.8-compatible tuple return annotation ## Test plan - [x] Build the native library from the latest `main` - [x] Run all 38 consolidated FSM builder tests with that branch-native library - [x] Run Black, isort, and Ruff checks - [x] Run repository pre-commit hooks
This was referenced Jul 30, 2026
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.
Changes
A finite-state machine (FSM) represents valid paths using states and transitions. Previously, the implementation built a small FSM for every sequence element and every choice branch, then copied those FSMs into a larger one. Large grammars therefore repeatedly created, copied, and destroyed short-lived objects.
This PR builds arbitrarily nested grammar expressions directly into a shared target FSM:
Correctness
Performance
Standalone FSM construction benchmarks:
Across four inputs, full grammar optimization time decreased by 10.2% to 20.2%. For a JSON Schema with 50,000 fields, the first full compilation dropped from 4440.5 ms to 4237.0 ms, a 4.6% reduction. This PR does not change allowed-token-set generation during decoding.