llguidance 0.7.12__tar.gz → 0.7.13__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {llguidance-0.7.12 → llguidance-0.7.13}/CHANGELOG.md +5 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/Cargo.lock +7 -7
- {llguidance-0.7.12 → llguidance-0.7.13}/PKG-INFO +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/src/json_stats.rs +3 -11
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/Cargo.toml +2 -2
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/llguidance.h +8 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/api.rs +8 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/lexer.rs +33 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/lexerspec.rs +2 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/parser.rs +33 -9
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/perf.rs +3 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/regexvec.rs +5 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/factory.rs +8 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/tokenparser.rs +6 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/pyproject.toml +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/__init__.py +2 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/_lib.pyi +86 -5
- {llguidance-0.7.12 → llguidance-0.7.13}/python/torch_tests/test_matcher.py +31 -7
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/Cargo.toml +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/src/lib.rs +2 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/src/llinterpreter.rs +6 -3
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/src/llmatcher.rs +10 -6
- llguidance-0.7.13/python_ext/src/parserlimits.rs +106 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/src/sample_parser.rs +19 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/Cargo.toml +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_downloader/Cargo.toml +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_tokenizers/Cargo.toml +1 -1
- {llguidance-0.7.12 → llguidance-0.7.13}/.github/workflows/rust.yml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/.github/workflows/wheels.yml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/.gitignore +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/CODE_OF_CONDUCT.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/Cargo.toml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/LICENSE +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/SECURITY.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/SUPPORT.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/c_sample/Makefile +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/c_sample/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/c_sample/c_sample.cpp +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/fast_forward.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/json_schema.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/mask_plot.png +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/optimizations.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/special_tokens.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/syntax.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/docs/toktrie.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/Cargo.toml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/expected_maskbench.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/jstats.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/scripts/split-stats.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/scripts/split_plot.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/src/lib.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/json_stats/src/stats.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/LICENSE +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/build.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/cbindgen.toml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/grammars/character.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/grammars/json.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/constraint.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/from_guidance.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/grammar.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/mod.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/earley/slicer.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/ffi.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/ffi_par.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/grammar_builder.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/compiler.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/context_ref.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/context_simple/context.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/context_simple/draft.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/context_simple/mod.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/formats.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/mod.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/numeric.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/schema.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json/shared_context.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/json_validation.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/ast.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/common.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/compiler.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/lexer.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/mod.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lark/parser.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/lib.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/logging.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/matcher.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/output.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/panic_utils.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/stop_controller.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/substring.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/parser/src/tokenizer_json.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/plan.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/_grammar_from.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/_struct_tag.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/_tokenizer.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/_util.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/cli.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/gbnf_to_lark.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/hf.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/mlx.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/numpy.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/py.typed +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/llguidance/torch.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/mypy.ini +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/torch_tests/__init__.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/torch_tests/test_bitmask.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python/torch_tests/test_hf.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/src/py.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/python_ext/src/pyjson.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/Cargo.toml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/cli.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/blog.sample.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/blog.schema.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/blog.schema.ll.json +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/arithmetic.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/c.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/chess.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/english.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/japanese.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/json.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/json_arr.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/list.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/from-llama.cpp/vllm-sql.gbnf +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/lark.lark +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/rfc.lark +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/data/rfc.xml +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/gtest.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/lark.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/run.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/src/lib.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/src/minimal.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/tests/test_lark.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/tests/test_ll.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/tests/test_raw_parser.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/sample_parser/tests/test_stop.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/annotate_asm.js +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/bump.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/cbindgen.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/checklinks.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/checklinks.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/ci-publish.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/disasm.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/gbnf_to_lark.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/gen-testcase.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/git-version.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/install-deps.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/jsonschema-stats.js +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/remote-guidance-test.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/rust-size.js +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/rust_size.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/test-guidance.sh +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/tokenizer_test.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/scripts/update-git.py +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/LICENSE +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/README.md +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/bytes.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/lib.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/recognizer.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/rng.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/svob.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/tokenv.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/src/toktree.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie/tests/test_svob.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_downloader/LICENSE +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_downloader/src/lib.rs +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_tokenizers/LICENSE +0 -0
- {llguidance-0.7.12 → llguidance-0.7.13}/toktrie_hf_tokenizers/src/lib.rs +0 -0
|
@@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. Dates are d
|
|
|
4
4
|
|
|
5
5
|
If a release doesn't introduce any interesting changes (build fixes etc.), it's skipped.
|
|
6
6
|
|
|
7
|
+
#### [0.7.13](https://github.com/guidance-ai/llguidance/compare/v0.7.12...0.7.13) 2025-04-05
|
|
8
|
+
|
|
9
|
+
- expose LLParserLimits in Python API [`598dc8f`](https://github.com/guidance-ai/llguidance/commit/598dc8f37f69f51244e54d9885445abf02a515a7)
|
|
10
|
+
- pre-compute lexer states for particularly large regexes (can be disabled in ParserLimits)
|
|
11
|
+
|
|
7
12
|
#### [0.7.12](https://github.com/guidance-ai/llguidance/compare/v0.7.11...0.7.12) 2025-04-04
|
|
8
13
|
|
|
9
14
|
- performance optimizations
|
|
@@ -401,9 +401,9 @@ dependencies = [
|
|
|
401
401
|
|
|
402
402
|
[[package]]
|
|
403
403
|
name = "derivre"
|
|
404
|
-
version = "0.3.
|
|
404
|
+
version = "0.3.5"
|
|
405
405
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
406
|
-
checksum = "
|
|
406
|
+
checksum = "2c15da97393af596fc344dc746f804c6742f1ddfd2e88fd7b75232a989c85c4e"
|
|
407
407
|
dependencies = [
|
|
408
408
|
"ahash",
|
|
409
409
|
"anyhow",
|
|
@@ -1177,7 +1177,7 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
|
|
1177
1177
|
|
|
1178
1178
|
[[package]]
|
|
1179
1179
|
name = "llguidance"
|
|
1180
|
-
version = "0.7.
|
|
1180
|
+
version = "0.7.13"
|
|
1181
1181
|
dependencies = [
|
|
1182
1182
|
"anyhow",
|
|
1183
1183
|
"derivre",
|
|
@@ -1196,7 +1196,7 @@ dependencies = [
|
|
|
1196
1196
|
|
|
1197
1197
|
[[package]]
|
|
1198
1198
|
name = "llguidance_py"
|
|
1199
|
-
version = "0.7.
|
|
1199
|
+
version = "0.7.13"
|
|
1200
1200
|
dependencies = [
|
|
1201
1201
|
"anyhow",
|
|
1202
1202
|
"bytemuck",
|
|
@@ -2356,7 +2356,7 @@ dependencies = [
|
|
|
2356
2356
|
|
|
2357
2357
|
[[package]]
|
|
2358
2358
|
name = "toktrie"
|
|
2359
|
-
version = "0.7.
|
|
2359
|
+
version = "0.7.13"
|
|
2360
2360
|
dependencies = [
|
|
2361
2361
|
"anyhow",
|
|
2362
2362
|
"bytemuck",
|
|
@@ -2367,7 +2367,7 @@ dependencies = [
|
|
|
2367
2367
|
|
|
2368
2368
|
[[package]]
|
|
2369
2369
|
name = "toktrie_hf_downloader"
|
|
2370
|
-
version = "0.7.
|
|
2370
|
+
version = "0.7.13"
|
|
2371
2371
|
dependencies = [
|
|
2372
2372
|
"anyhow",
|
|
2373
2373
|
"hf-hub",
|
|
@@ -2378,7 +2378,7 @@ dependencies = [
|
|
|
2378
2378
|
|
|
2379
2379
|
[[package]]
|
|
2380
2380
|
name = "toktrie_hf_tokenizers"
|
|
2381
|
-
version = "0.7.
|
|
2381
|
+
version = "0.7.13"
|
|
2382
2382
|
dependencies = [
|
|
2383
2383
|
"anyhow",
|
|
2384
2384
|
"log",
|
|
@@ -5,11 +5,7 @@ use json_stats::SchemaStats;
|
|
|
5
5
|
use jsonschema::Validator;
|
|
6
6
|
use llguidance::{
|
|
7
7
|
api::{GrammarInit, StopReason, TopLevelGrammar},
|
|
8
|
-
earley::{
|
|
9
|
-
perf::{num_with_commas, ParserPerfCounters},
|
|
10
|
-
regexvec::LexerStats,
|
|
11
|
-
XorShift,
|
|
12
|
-
},
|
|
8
|
+
earley::{perf::num_with_commas, regexvec::LexerStats, XorShift},
|
|
13
9
|
toktrie::{InferenceCapabilities, SimpleVob, TokEnv},
|
|
14
10
|
Constraint, HashMap, JsonCompileOptions, ParserFactory, TokenParser,
|
|
15
11
|
};
|
|
@@ -290,7 +286,6 @@ struct TestEnv {
|
|
|
290
286
|
factory: Arc<ParserFactory>,
|
|
291
287
|
ref_factory: Arc<ParserFactory>,
|
|
292
288
|
file_name: String,
|
|
293
|
-
perf_counters: Arc<ParserPerfCounters>,
|
|
294
289
|
hash_rnd: Arc<ahash::RandomState>,
|
|
295
290
|
}
|
|
296
291
|
|
|
@@ -739,8 +734,7 @@ impl TestEnv {
|
|
|
739
734
|
|
|
740
735
|
let t2 = std::time::Instant::now();
|
|
741
736
|
let parser = match parser {
|
|
742
|
-
Ok(
|
|
743
|
-
parser.parser.set_perf_counters(self.perf_counters.clone());
|
|
737
|
+
Ok(parser) => {
|
|
744
738
|
let mut constraint = Constraint::new(parser.clone());
|
|
745
739
|
constraint.compute_mask().unwrap();
|
|
746
740
|
res.first_mask_us = t2.elapsed().as_micros() as usize;
|
|
@@ -996,7 +990,6 @@ fn main() {
|
|
|
996
990
|
|
|
997
991
|
let t0 = std::time::Instant::now();
|
|
998
992
|
let par = num_threads > 1;
|
|
999
|
-
let perf_counters = Arc::new(ParserPerfCounters::new());
|
|
1000
993
|
let hash_rnd = Arc::new(ahash::RandomState::new());
|
|
1001
994
|
let do_file = |file: &String| {
|
|
1002
995
|
let env = TestEnv {
|
|
@@ -1005,7 +998,6 @@ fn main() {
|
|
|
1005
998
|
ref_factory: ref_factory.clone(),
|
|
1006
999
|
file_name: file.to_string(),
|
|
1007
1000
|
cli: options.clone(),
|
|
1008
|
-
perf_counters: perf_counters.clone(),
|
|
1009
1001
|
hash_rnd: hash_rnd.clone(),
|
|
1010
1002
|
};
|
|
1011
1003
|
env.run_test()
|
|
@@ -1155,7 +1147,7 @@ fn main() {
|
|
|
1155
1147
|
eprintln!(
|
|
1156
1148
|
"{}\n{}",
|
|
1157
1149
|
serde_json::to_string_pretty(&total).unwrap(),
|
|
1158
|
-
perf_counters
|
|
1150
|
+
&factory.perf_counters(),
|
|
1159
1151
|
);
|
|
1160
1152
|
}
|
|
1161
1153
|
eprintln!(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "llguidance"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.13"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
description = "Super-fast Structured Outputs"
|
|
@@ -8,7 +8,7 @@ repository = "https://github.com/guidance-ai/llguidance"
|
|
|
8
8
|
|
|
9
9
|
[dependencies]
|
|
10
10
|
toktrie = { workspace = true }
|
|
11
|
-
derivre = { version = "=0.3.
|
|
11
|
+
derivre = { version = "=0.3.5", default-features = false, features = ["compress"] }
|
|
12
12
|
serde = { version = "1.0.217", features = ["derive"] }
|
|
13
13
|
serde_json = { version = "1.0.138", features = ["preserve_order"] }
|
|
14
14
|
anyhow = "1.0.95"
|
|
@@ -70,6 +70,14 @@ typedef struct LlgParserLimits {
|
|
|
70
70
|
* Default: 500_000 (a few megabytes of JSON)
|
|
71
71
|
*/
|
|
72
72
|
size_t max_grammar_size;
|
|
73
|
+
/**
|
|
74
|
+
* If true, we'll run any extremely large regexes against the whole
|
|
75
|
+
* trie of the tokenizer while constructing the lexer.
|
|
76
|
+
* This reduces future mask computation time, but increases
|
|
77
|
+
* the time it takes to construct the lexer.
|
|
78
|
+
* Default: true
|
|
79
|
+
*/
|
|
80
|
+
bool precompute_large_lexemes;
|
|
73
81
|
} LlgParserLimits;
|
|
74
82
|
|
|
75
83
|
typedef struct LlgConstraintInit {
|
|
@@ -249,6 +249,13 @@ pub struct ParserLimits {
|
|
|
249
249
|
/// Maximum size of the grammar (symbols in productions)
|
|
250
250
|
/// Default: 500_000 (a few megabytes of JSON)
|
|
251
251
|
pub max_grammar_size: usize,
|
|
252
|
+
|
|
253
|
+
/// If true, we'll run any extremely large regexes against the whole
|
|
254
|
+
/// trie of the tokenizer while constructing the lexer.
|
|
255
|
+
/// This reduces future mask computation time, but increases
|
|
256
|
+
/// the time it takes to construct the lexer.
|
|
257
|
+
/// Default: true
|
|
258
|
+
pub precompute_large_lexemes: bool,
|
|
252
259
|
}
|
|
253
260
|
|
|
254
261
|
impl Default for ParserLimits {
|
|
@@ -260,6 +267,7 @@ impl Default for ParserLimits {
|
|
|
260
267
|
max_lexer_states: 250_000, //
|
|
261
268
|
max_grammar_size: 500_000, // fhir schema => 200k
|
|
262
269
|
step_max_items: 50_000, //
|
|
270
|
+
precompute_large_lexemes: true,
|
|
263
271
|
}
|
|
264
272
|
}
|
|
265
273
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
use anyhow::Result;
|
|
2
2
|
use std::fmt::Debug;
|
|
3
|
-
use toktrie::SimpleVob;
|
|
3
|
+
use toktrie::{Recognizer, SimpleVob, TokTrie};
|
|
4
4
|
|
|
5
5
|
use crate::api::ParserLimits;
|
|
6
6
|
|
|
@@ -59,6 +59,29 @@ pub enum LexerResult {
|
|
|
59
59
|
Error,
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
struct LexerPrecomputer<'a> {
|
|
63
|
+
states: Vec<StateID>,
|
|
64
|
+
lex: &'a mut Lexer,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
impl Recognizer for LexerPrecomputer<'_> {
|
|
68
|
+
fn collapse(&mut self) {}
|
|
69
|
+
fn trie_finished(&mut self) {}
|
|
70
|
+
fn pop_bytes(&mut self, num: usize) {
|
|
71
|
+
self.states.truncate(self.states.len() - num);
|
|
72
|
+
}
|
|
73
|
+
fn try_push_byte(&mut self, byte: u8) -> bool {
|
|
74
|
+
let state = *self.states.last().unwrap();
|
|
75
|
+
match self.lex.advance(state, byte, false) {
|
|
76
|
+
LexerResult::State(next_state, _) => {
|
|
77
|
+
self.states.push(next_state);
|
|
78
|
+
true
|
|
79
|
+
}
|
|
80
|
+
_ => false,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
62
85
|
impl Lexer {
|
|
63
86
|
pub fn from(spec: &LexerSpec, limits: &mut ParserLimits, dbg: bool) -> Result<Self> {
|
|
64
87
|
let mut dfa = spec.to_regex_vec(limits)?;
|
|
@@ -92,6 +115,15 @@ impl Lexer {
|
|
|
92
115
|
self.dfa.initial_state(allowed_lexemes)
|
|
93
116
|
}
|
|
94
117
|
|
|
118
|
+
pub fn precompute_for(&mut self, trie: &TokTrie, allowed_lexemes: &LexemeSet) {
|
|
119
|
+
let state = self.start_state(allowed_lexemes);
|
|
120
|
+
let mut states = Vec::with_capacity(300);
|
|
121
|
+
states.push(state);
|
|
122
|
+
let mut pre = LexerPrecomputer { states, lex: self };
|
|
123
|
+
let mut toks = trie.alloc_token_set();
|
|
124
|
+
trie.add_bias(&mut pre, &mut toks, &[]);
|
|
125
|
+
}
|
|
126
|
+
|
|
95
127
|
pub fn transition_start_state(&mut self, s: StateID, first_byte: Option<u8>) -> StateID {
|
|
96
128
|
first_byte.map(|b| self.dfa.transition(s, b)).unwrap_or(s)
|
|
97
129
|
}
|
|
@@ -48,7 +48,7 @@ pub struct LexemeSpec {
|
|
|
48
48
|
pub(crate) name: String,
|
|
49
49
|
pub(crate) rx: RegexAst,
|
|
50
50
|
class: LexemeClass,
|
|
51
|
-
compiled_rx: ExprRef,
|
|
51
|
+
pub(crate) compiled_rx: ExprRef,
|
|
52
52
|
ends_at_eos: bool,
|
|
53
53
|
lazy: bool,
|
|
54
54
|
contextual: bool,
|
|
@@ -299,6 +299,7 @@ impl LexerSpec {
|
|
|
299
299
|
} else {
|
|
300
300
|
compiled
|
|
301
301
|
};
|
|
302
|
+
|
|
302
303
|
if let Some(idx) = self.lexemes.iter().position(|lex| {
|
|
303
304
|
lex.compiled_rx == compiled
|
|
304
305
|
&& lex.class == spec.class
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
// (Retrieved 18 Sep 2024).
|
|
6
6
|
|
|
7
7
|
use std::{
|
|
8
|
-
fmt::Debug,
|
|
8
|
+
fmt::{Debug, Display},
|
|
9
9
|
hash::Hash,
|
|
10
10
|
ops::Range,
|
|
11
11
|
sync::{Arc, Mutex},
|
|
@@ -207,6 +207,12 @@ impl ParserStats {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
impl Display for ParserStats {
|
|
211
|
+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
212
|
+
write!(f, "{}", serde_json::to_string_pretty(self).unwrap())
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
210
216
|
id32_type!(GrammarStackPtr);
|
|
211
217
|
|
|
212
218
|
#[derive(Clone, Debug)]
|
|
@@ -580,9 +586,26 @@ impl ParserState {
|
|
|
580
586
|
tok_env: TokEnv,
|
|
581
587
|
grammar: Arc<CGrammar>,
|
|
582
588
|
mut limits: ParserLimits,
|
|
589
|
+
perf_counters: Arc<ParserPerfCounters>,
|
|
583
590
|
) -> Result<(Self, Lexer)> {
|
|
584
591
|
let start = grammar.start();
|
|
585
|
-
let lexer = Lexer::from(grammar.lexer_spec(), &mut limits, true)?;
|
|
592
|
+
let mut lexer = Lexer::from(grammar.lexer_spec(), &mut limits, true)?;
|
|
593
|
+
if limits.precompute_large_lexemes {
|
|
594
|
+
let t0 = crate::Instant::now();
|
|
595
|
+
for spec in &grammar.lexer_spec().lexemes {
|
|
596
|
+
let w = lexer.dfa.lexeme_weight(spec.idx);
|
|
597
|
+
if w > 1000 {
|
|
598
|
+
// println!(
|
|
599
|
+
// "precomputing lexeme {} (w={w})",
|
|
600
|
+
// lexer.lexer_spec().lexeme_def_to_string(spec.idx)
|
|
601
|
+
// );
|
|
602
|
+
let mut allowed = grammar.lexer_spec().alloc_lexeme_set();
|
|
603
|
+
allowed.add(spec.idx);
|
|
604
|
+
lexer.precompute_for(tok_env.tok_trie(), &allowed);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
perf_counters.precompute.record(t0.elapsed());
|
|
608
|
+
}
|
|
586
609
|
let scratch = Scratch::new(Arc::clone(&grammar));
|
|
587
610
|
let lexer_state = lexer.a_dead_state(); // placeholder
|
|
588
611
|
let spec_tok = tok_env
|
|
@@ -626,7 +649,7 @@ impl ParserState {
|
|
|
626
649
|
shared_box: Box::new(SharedState {
|
|
627
650
|
lexer_opt: Some(lexer),
|
|
628
651
|
}),
|
|
629
|
-
perf_counters
|
|
652
|
+
perf_counters,
|
|
630
653
|
};
|
|
631
654
|
|
|
632
655
|
r.scratch.grammar_stack.push(GrammarStackNode {
|
|
@@ -2576,8 +2599,13 @@ impl ParserError {
|
|
|
2576
2599
|
}
|
|
2577
2600
|
|
|
2578
2601
|
impl Parser {
|
|
2579
|
-
pub fn new(
|
|
2580
|
-
|
|
2602
|
+
pub fn new(
|
|
2603
|
+
tok_env: TokEnv,
|
|
2604
|
+
grammar: Arc<CGrammar>,
|
|
2605
|
+
limits: ParserLimits,
|
|
2606
|
+
perf_counters: Arc<ParserPerfCounters>,
|
|
2607
|
+
) -> Result<Self> {
|
|
2608
|
+
let (state, lexer) = ParserState::new(tok_env, grammar, limits, perf_counters)?;
|
|
2581
2609
|
let shared = Arc::new(Mutex::new(Box::new(SharedState {
|
|
2582
2610
|
lexer_opt: Some(lexer),
|
|
2583
2611
|
})));
|
|
@@ -2603,10 +2631,6 @@ impl Parser {
|
|
|
2603
2631
|
&self.state.stats
|
|
2604
2632
|
}
|
|
2605
2633
|
|
|
2606
|
-
pub fn set_perf_counters(&mut self, counters: Arc<ParserPerfCounters>) {
|
|
2607
|
-
self.state.perf_counters = counters;
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
2634
|
#[inline(always)]
|
|
2611
2635
|
pub fn perf_counters(&self) -> &ParserPerfCounters {
|
|
2612
2636
|
&self.state.perf_counters
|
|
@@ -87,6 +87,7 @@ pub struct ParserPerfCounters {
|
|
|
87
87
|
pub tokenize_ff: PerfTimer,
|
|
88
88
|
pub compute_bias: PerfTimer,
|
|
89
89
|
pub compute_mask: PerfTimer,
|
|
90
|
+
pub precompute: PerfTimer,
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
impl Default for ParserPerfCounters {
|
|
@@ -104,6 +105,7 @@ impl ParserPerfCounters {
|
|
|
104
105
|
tokenize_ff: PerfTimer::new("tokenize_ff"),
|
|
105
106
|
compute_bias: PerfTimer::new("compute_bias"),
|
|
106
107
|
compute_mask: PerfTimer::new("compute_mask"),
|
|
108
|
+
precompute: PerfTimer::new("precompute"),
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
@@ -115,6 +117,7 @@ impl ParserPerfCounters {
|
|
|
115
117
|
&self.compute_bias,
|
|
116
118
|
&self.compute_mask,
|
|
117
119
|
&self.tmp_counter,
|
|
120
|
+
&self.precompute,
|
|
118
121
|
]
|
|
119
122
|
}
|
|
120
123
|
}
|
|
@@ -490,6 +490,11 @@ impl RegexVec {
|
|
|
490
490
|
self.exprs.cost()
|
|
491
491
|
}
|
|
492
492
|
|
|
493
|
+
pub fn lexeme_weight(&mut self, lexeme_idx: LexemeIdx) -> u32 {
|
|
494
|
+
let e = self.rx_list[lexeme_idx.as_usize()];
|
|
495
|
+
self.exprs.get_weight(e)
|
|
496
|
+
}
|
|
497
|
+
|
|
493
498
|
pub fn set_max_states(&mut self, max_states: usize) {
|
|
494
499
|
if !self.has_error() {
|
|
495
500
|
self.max_states = max_states;
|
|
@@ -5,7 +5,7 @@ use toktrie::{InferenceCapabilities, TokEnv};
|
|
|
5
5
|
|
|
6
6
|
use crate::{
|
|
7
7
|
api::{GrammarInit, ParserLimits, TopLevelGrammar},
|
|
8
|
-
earley::{SlicedBiasComputer, XorShift},
|
|
8
|
+
earley::{perf::ParserPerfCounters, SlicedBiasComputer, XorShift},
|
|
9
9
|
Logger, TokenParser,
|
|
10
10
|
};
|
|
11
11
|
|
|
@@ -17,6 +17,7 @@ pub struct ParserFactory {
|
|
|
17
17
|
buffer_log_level: u32,
|
|
18
18
|
limits: ParserLimits,
|
|
19
19
|
seed: Mutex<XorShift>,
|
|
20
|
+
perf_counters: Arc<ParserPerfCounters>,
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
impl ParserFactory {
|
|
@@ -34,9 +35,14 @@ impl ParserFactory {
|
|
|
34
35
|
buffer_log_level: 0,
|
|
35
36
|
seed: Mutex::new(XorShift::default()),
|
|
36
37
|
limits: ParserLimits::default(),
|
|
38
|
+
perf_counters: Arc::new(ParserPerfCounters::default()),
|
|
37
39
|
})
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
pub fn perf_counters(&self) -> Arc<ParserPerfCounters> {
|
|
43
|
+
self.perf_counters.clone()
|
|
44
|
+
}
|
|
45
|
+
|
|
40
46
|
pub fn new_simple(tok_env: &TokEnv) -> Result<Self> {
|
|
41
47
|
Self::new(
|
|
42
48
|
tok_env,
|
|
@@ -55,6 +61,7 @@ impl ParserFactory {
|
|
|
55
61
|
buffer_log_level: self.buffer_log_level,
|
|
56
62
|
seed: Mutex::new(XorShift::default()),
|
|
57
63
|
limits: self.limits.clone(),
|
|
64
|
+
perf_counters: self.perf_counters.clone(),
|
|
58
65
|
})
|
|
59
66
|
}
|
|
60
67
|
|
|
@@ -80,7 +80,12 @@ impl TokenParser {
|
|
|
80
80
|
limits.clone(),
|
|
81
81
|
factory.extra_lexemes(),
|
|
82
82
|
)?;
|
|
83
|
-
let mut parser = Parser::new(
|
|
83
|
+
let mut parser = Parser::new(
|
|
84
|
+
token_env.clone(),
|
|
85
|
+
compiled_grammar,
|
|
86
|
+
limits.clone(),
|
|
87
|
+
factory.perf_counters(),
|
|
88
|
+
)?;
|
|
84
89
|
parser.metrics_mut().rand = factory.next_rng();
|
|
85
90
|
let eos_token = token_env.tok_trie().eos_token();
|
|
86
91
|
|
|
@@ -6,6 +6,7 @@ from ._lib import (
|
|
|
6
6
|
RegexCompiler,
|
|
7
7
|
LLExecutor,
|
|
8
8
|
LLMatcher,
|
|
9
|
+
LLParserLimits,
|
|
9
10
|
)
|
|
10
11
|
from ._tokenizer import TokenizerWrapper
|
|
11
12
|
from ._grammar_from import GrammarFormat, grammar_from
|
|
@@ -16,6 +17,7 @@ __all__ = [
|
|
|
16
17
|
"LLMatcher",
|
|
17
18
|
"LLInterpreter",
|
|
18
19
|
"LLExecutor",
|
|
20
|
+
"LLParserLimits",
|
|
19
21
|
"JsonCompiler",
|
|
20
22
|
"LarkCompiler",
|
|
21
23
|
"RegexCompiler",
|
|
@@ -121,9 +121,11 @@ class LLInterpreter:
|
|
|
121
121
|
cls,
|
|
122
122
|
tokenizer: LLTokenizer,
|
|
123
123
|
grammar: str,
|
|
124
|
+
/,
|
|
124
125
|
enable_backtrack: bool = True,
|
|
125
126
|
enable_ff_tokens: bool = True,
|
|
126
127
|
log_level: int = 1,
|
|
128
|
+
limits: Optional[LLParserLimits] = None,
|
|
127
129
|
) -> "LLInterpreter":
|
|
128
130
|
"""
|
|
129
131
|
Create a new interpreter.
|
|
@@ -218,10 +220,14 @@ class LLInterpreter:
|
|
|
218
220
|
|
|
219
221
|
class LLMatcher:
|
|
220
222
|
|
|
221
|
-
def __new__(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
223
|
+
def __new__(
|
|
224
|
+
cls,
|
|
225
|
+
tokenizer: LLTokenizer,
|
|
226
|
+
grammar: str,
|
|
227
|
+
/,
|
|
228
|
+
log_level: int = 1,
|
|
229
|
+
limits: Optional[LLParserLimits] = None,
|
|
230
|
+
) -> "LLMatcher":
|
|
225
231
|
"""
|
|
226
232
|
Create a new LLMatcher.
|
|
227
233
|
Args:
|
|
@@ -246,7 +252,8 @@ class LLMatcher:
|
|
|
246
252
|
"""
|
|
247
253
|
|
|
248
254
|
@staticmethod
|
|
249
|
-
def validate_grammar(grammar: str,
|
|
255
|
+
def validate_grammar(grammar: str,
|
|
256
|
+
tokenizer: Optional[LLTokenizer] = None) -> str:
|
|
250
257
|
"""
|
|
251
258
|
Validate the grammar, for example one returned by LLMatcher.grammar_from_*().
|
|
252
259
|
Returns empty string if the grammar is valid, otherwise an error message.
|
|
@@ -504,3 +511,77 @@ class JsonCompileOptions(TypedDict, total=False):
|
|
|
504
511
|
whitespace_flexible: Optional[bool]
|
|
505
512
|
# defaults to false
|
|
506
513
|
coerce_one_of: Optional[bool]
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
class LLParserLimits:
|
|
517
|
+
|
|
518
|
+
def __init__(
|
|
519
|
+
self,
|
|
520
|
+
max_items_in_row: Optional[int] = None,
|
|
521
|
+
initial_lexer_fuel: Optional[int] = None,
|
|
522
|
+
step_lexer_fuel: Optional[int] = None,
|
|
523
|
+
step_max_items: Optional[int] = None,
|
|
524
|
+
max_lexer_states: Optional[int] = None,
|
|
525
|
+
max_grammar_size: Optional[int] = None,
|
|
526
|
+
precompute_large_lexemes: Optional[bool] = None,
|
|
527
|
+
) -> None:
|
|
528
|
+
"""
|
|
529
|
+
ParserLimits configuration for controlling parser and lexer resource usage.
|
|
530
|
+
|
|
531
|
+
Args:
|
|
532
|
+
max_items_in_row (Optional[int]):
|
|
533
|
+
Maximum branching factor for a single production row in the grammar.
|
|
534
|
+
Affects ambiguity and parsing explosion risk. Default: 2000.
|
|
535
|
+
|
|
536
|
+
initial_lexer_fuel (Optional[int]):
|
|
537
|
+
Fuel for building the initial regex ASTs in the lexer.
|
|
538
|
+
Limits complexity of regex analysis. Speed: ~50k/ms. Default: 1_000_000.
|
|
539
|
+
|
|
540
|
+
step_lexer_fuel (Optional[int]):
|
|
541
|
+
Maximum fuel used during a single lexer mask computation step.
|
|
542
|
+
Controls performance per token analysis phase. Speed: ~14k/ms. Default: 200_000.
|
|
543
|
+
|
|
544
|
+
step_max_items (Optional[int]):
|
|
545
|
+
Cap on the number of Earley items generated per mask step.
|
|
546
|
+
Controls parsing granularity and performance. Speed: ~20k/ms. Default: 50_000.
|
|
547
|
+
|
|
548
|
+
max_lexer_states (Optional[int]):
|
|
549
|
+
Maximum number of distinct states the lexer can construct.
|
|
550
|
+
Affects memory use (approx. 1–2kB per state). Default: 250_000.
|
|
551
|
+
|
|
552
|
+
max_grammar_size (Optional[int]):
|
|
553
|
+
Maximum number of symbols in grammar productions.
|
|
554
|
+
Acts as a limit on total grammar complexity and size. Default: 500_000.
|
|
555
|
+
|
|
556
|
+
precompute_large_lexemes (Optional[bool]):
|
|
557
|
+
Whether to run large regexes eagerly on the entire token trie during lexer build.
|
|
558
|
+
Increases lexer construction time, but speeds up mask computation. Default: True.
|
|
559
|
+
"""
|
|
560
|
+
|
|
561
|
+
@property
|
|
562
|
+
def max_items_in_row(self) -> int:
|
|
563
|
+
"""Maximum branching factor for a grammar row. Default: 2000"""
|
|
564
|
+
|
|
565
|
+
@property
|
|
566
|
+
def initial_lexer_fuel(self) -> int:
|
|
567
|
+
"""Fuel used to build initial lexer regex ASTs. Default: 1_000_000"""
|
|
568
|
+
|
|
569
|
+
@property
|
|
570
|
+
def step_lexer_fuel(self) -> int:
|
|
571
|
+
"""Lexer fuel for mask computation steps. Default: 200_000"""
|
|
572
|
+
|
|
573
|
+
@property
|
|
574
|
+
def step_max_items(self) -> int:
|
|
575
|
+
"""Maximum Earley items per step. Default: 50_000"""
|
|
576
|
+
|
|
577
|
+
@property
|
|
578
|
+
def max_lexer_states(self) -> int:
|
|
579
|
+
"""Maximum lexer states (affects memory). Default: 250_000"""
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def max_grammar_size(self) -> int:
|
|
583
|
+
"""Maximum grammar size (symbols in productions). Default: 500_000"""
|
|
584
|
+
|
|
585
|
+
@property
|
|
586
|
+
def precompute_large_lexemes(self) -> bool:
|
|
587
|
+
"""Precompute large regexes during lexer construction. Default: True"""
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Any, Dict, List, Tuple, Union
|
|
2
2
|
import llguidance
|
|
3
3
|
from llguidance.numpy import fill_next_token_bitmask_par, allocate_token_bitmask
|
|
4
|
-
from llguidance import LLMatcher, LLTokenizer, StructTag
|
|
4
|
+
from llguidance import LLMatcher, LLTokenizer, StructTag, LLParserLimits
|
|
5
5
|
import pytest
|
|
6
6
|
from numpy.typing import NDArray
|
|
7
7
|
import numpy as np
|
|
@@ -42,7 +42,7 @@ def check_one_grammar(grm: str, s: str, passing: bool) -> None:
|
|
|
42
42
|
del tokens[-1]
|
|
43
43
|
else:
|
|
44
44
|
tokens = tokenizer().tokenize_str(s)
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
print("Check: " + tokenizer().dbg_tokens(tokens))
|
|
47
47
|
|
|
48
48
|
for i, t in enumerate(tokens):
|
|
@@ -74,8 +74,7 @@ def check_one_grammar(grm: str, s: str, passing: bool) -> None:
|
|
|
74
74
|
assert interp.is_accepting()
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def check_grammar(grm: str, passing: List[str],
|
|
78
|
-
failing: List[str]) -> None:
|
|
77
|
+
def check_grammar(grm: str, passing: List[str], failing: List[str]) -> None:
|
|
79
78
|
for s in passing:
|
|
80
79
|
check_one_grammar(grm, s, True)
|
|
81
80
|
for s in failing:
|
|
@@ -391,6 +390,31 @@ def test_struct_tag_0() -> None:
|
|
|
391
390
|
# this should pass since it doesn't actually use special tokens:
|
|
392
391
|
'<|tool|>qux(1)',
|
|
393
392
|
],
|
|
394
|
-
[
|
|
395
|
-
|
|
396
|
-
|
|
393
|
+
["⁂<|tool|>qux(11)"])
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def test_parser_limits() -> None:
|
|
397
|
+
# this one needs more than initial_lexer_fuel=20
|
|
398
|
+
m = LLMatcher(tokenizer(),
|
|
399
|
+
"start: /(foo[12]23|bar)/",
|
|
400
|
+
limits=LLParserLimits(initial_lexer_fuel=5))
|
|
401
|
+
assert "initial lexer configuration (grammar) too big" in m.get_error()
|
|
402
|
+
|
|
403
|
+
# m = LLMatcher(tokenizer(),
|
|
404
|
+
# "start: /(foo[12]23|bar|qux|mux)/",
|
|
405
|
+
# limits=LLParserLimits(
|
|
406
|
+
# step_lexer_fuel=1,
|
|
407
|
+
# precompute_large_lexemes=False,
|
|
408
|
+
# ),
|
|
409
|
+
# log_level=2)
|
|
410
|
+
# toks = tokenizer().tokenize_str("foo223")
|
|
411
|
+
# assert not m.get_error()
|
|
412
|
+
# m.consume_token(toks[0])
|
|
413
|
+
# mask = m.compute_logit_bias()
|
|
414
|
+
# assert not m.get_error()
|
|
415
|
+
# m.consume_token(toks[1])
|
|
416
|
+
# mask = m.compute_logit_bias()
|
|
417
|
+
# assert not m.get_error()
|
|
418
|
+
# m.consume_token(toks[2])
|
|
419
|
+
# mask = m.compute_logit_bias()
|
|
420
|
+
# assert not m.get_error()
|
|
@@ -2,6 +2,7 @@ use pyo3::prelude::*;
|
|
|
2
2
|
|
|
3
3
|
mod llinterpreter;
|
|
4
4
|
mod llmatcher;
|
|
5
|
+
mod parserlimits;
|
|
5
6
|
mod py;
|
|
6
7
|
mod pyjson;
|
|
7
8
|
|
|
@@ -9,6 +10,7 @@ mod pyjson;
|
|
|
9
10
|
#[pymodule]
|
|
10
11
|
fn _lib(_py: Python<'_>, m: &Bound<PyModule>) -> PyResult<()> {
|
|
11
12
|
py::init(m)?;
|
|
13
|
+
parserlimits::init(m)?;
|
|
12
14
|
llinterpreter::init(m)?;
|
|
13
15
|
llmatcher::init(m)?;
|
|
14
16
|
Ok(())
|