gramson 0.1.0__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.
Files changed (89) hide show
  1. gramson-0.1.0/LICENSE +21 -0
  2. gramson-0.1.0/MANIFEST.in +9 -0
  3. gramson-0.1.0/Makefile +65 -0
  4. gramson-0.1.0/PKG-INFO +180 -0
  5. gramson-0.1.0/README.md +111 -0
  6. gramson-0.1.0/THIRD_PARTY_NOTICES.md +15 -0
  7. gramson-0.1.0/docs/DESIGN.md +55 -0
  8. gramson-0.1.0/docs/DEVELOPMENT.md +111 -0
  9. gramson-0.1.0/docs/PYPI.md +149 -0
  10. gramson-0.1.0/docs/README.md +90 -0
  11. gramson-0.1.0/docs/USAGE.md +144 -0
  12. gramson-0.1.0/docs/index.html +25 -0
  13. gramson-0.1.0/docs/json-value.schema.yaml +22 -0
  14. gramson-0.1.0/docs/openapi.yaml +74 -0
  15. gramson-0.1.0/examples/bitwise/README.md +115 -0
  16. gramson-0.1.0/examples/bitwise/expressions/conversions.json +10 -0
  17. gramson-0.1.0/examples/bitwise/expressions/conversions.yaml +5 -0
  18. gramson-0.1.0/examples/bitwise/expressions/invalid-arity.yaml +1 -0
  19. gramson-0.1.0/examples/bitwise/expressions/invalid-conversion-arity.yaml +1 -0
  20. gramson-0.1.0/examples/bitwise/expressions/nested.json +7 -0
  21. gramson-0.1.0/examples/bitwise/expressions/nested.yaml +13 -0
  22. gramson-0.1.0/examples/bitwise/language.yaml +3 -0
  23. gramson-0.1.0/examples/extension/README.md +62 -0
  24. gramson-0.1.0/examples/extension/custom/wrapping.yaml +9 -0
  25. gramson-0.1.0/examples/extension/expressions/invalid-arity.yaml +1 -0
  26. gramson-0.1.0/examples/extension/expressions/nested.json +6 -0
  27. gramson-0.1.0/examples/extension/expressions/nested.yaml +5 -0
  28. gramson-0.1.0/examples/extension/expressions/wrap-only.yaml +3 -0
  29. gramson-0.1.0/examples/extension/language.yaml +4 -0
  30. gramson-0.1.0/examples/extension/standalone.yaml +2 -0
  31. gramson-0.1.0/examples/external/README.md +73 -0
  32. gramson-0.1.0/examples/external/expressions/invalid-arity.yaml +1 -0
  33. gramson-0.1.0/examples/external/expressions/nested.json +3 -0
  34. gramson-0.1.0/examples/external/expressions/nested.yaml +6 -0
  35. gramson-0.1.0/examples/external/language.yaml +3 -0
  36. gramson-0.1.0/examples/external/vendor/mystuff/myops/wrapping.yaml +7 -0
  37. gramson-0.1.0/examples/invalid.json +349 -0
  38. gramson-0.1.0/examples/valid.json +851 -0
  39. gramson-0.1.0/gramson/__init__.py +1 -0
  40. gramson-0.1.0/gramson/__main__.py +3 -0
  41. gramson-0.1.0/gramson/cli.py +195 -0
  42. gramson-0.1.0/gramson/generation.py +366 -0
  43. gramson-0.1.0/gramson.egg-info/PKG-INFO +180 -0
  44. gramson-0.1.0/gramson.egg-info/SOURCES.txt +87 -0
  45. gramson-0.1.0/gramson.egg-info/dependency_links.txt +1 -0
  46. gramson-0.1.0/gramson.egg-info/entry_points.txt +2 -0
  47. gramson-0.1.0/gramson.egg-info/requires.txt +3 -0
  48. gramson-0.1.0/gramson.egg-info/top_level.txt +1 -0
  49. gramson-0.1.0/pyproject.toml +60 -0
  50. gramson-0.1.0/requirements-dev.txt +4 -0
  51. gramson-0.1.0/requirements-release.txt +3 -0
  52. gramson-0.1.0/schema/__init__.py +1 -0
  53. gramson-0.1.0/schema/core/arithmetic.schema.yaml +121 -0
  54. gramson-0.1.0/schema/core/collection.schema.yaml +146 -0
  55. gramson-0.1.0/schema/core/comparison.schema.yaml +131 -0
  56. gramson-0.1.0/schema/core/data.schema.yaml +65 -0
  57. gramson-0.1.0/schema/core/debugging.schema.yaml +24 -0
  58. gramson-0.1.0/schema/core/logic.schema.yaml +129 -0
  59. gramson-0.1.0/schema/core/string.schema.yaml +38 -0
  60. gramson-0.1.0/schema/expression.schema.yaml +48 -0
  61. gramson-0.1.0/schema/shared.schema.yaml +9 -0
  62. gramson-0.1.0/setup.cfg +4 -0
  63. gramson-0.1.0/spec/README.md +302 -0
  64. gramson-0.1.0/spec/__init__.py +1 -0
  65. gramson-0.1.0/spec/core/arithmetic.yaml +52 -0
  66. gramson-0.1.0/spec/core/collection.yaml +70 -0
  67. gramson-0.1.0/spec/core/comparison.yaml +64 -0
  68. gramson-0.1.0/spec/core/data.yaml +29 -0
  69. gramson-0.1.0/spec/core/debugging.yaml +10 -0
  70. gramson-0.1.0/spec/core/logic.yaml +58 -0
  71. gramson-0.1.0/spec/core/string.yaml +16 -0
  72. gramson-0.1.0/spec/extensions/bitwise.yaml +67 -0
  73. gramson-0.1.0/spec/language.yaml +2 -0
  74. gramson-0.1.0/tests/jsonlogic_exclusions.json +1 -0
  75. gramson-0.1.0/tests/schema_support.py +21 -0
  76. gramson-0.1.0/tests/test_bitwise.py +82 -0
  77. gramson-0.1.0/tests/test_cli.py +292 -0
  78. gramson-0.1.0/tests/test_external_includes.py +164 -0
  79. gramson-0.1.0/tests/test_generation.py +249 -0
  80. gramson-0.1.0/tests/test_jsonlogic.py +72 -0
  81. gramson-0.1.0/tests/test_language.py +299 -0
  82. gramson-0.1.0/tests/test_openapi.py +130 -0
  83. gramson-0.1.0/tests/test_validation.py +47 -0
  84. gramson-0.1.0/tests/vendor/jsonlogic/LICENSE +22 -0
  85. gramson-0.1.0/tests/vendor/jsonlogic/README.md +48 -0
  86. gramson-0.1.0/tests/vendor/jsonlogic/snapshot.json +20 -0
  87. gramson-0.1.0/tests/vendor/jsonlogic/tests.json +532 -0
  88. gramson-0.1.0/tools/check_distribution.py +172 -0
  89. gramson-0.1.0/tools/generate_schema.py +33 -0
gramson-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kim Bäckström
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include README.md Makefile requirements-dev.txt requirements-release.txt
2
+ recursive-include spec *.yaml *.yml *.md
3
+ recursive-include schema *.schema.yaml
4
+ recursive-include tools *.py
5
+ recursive-include tests *.py *.json *.md LICENSE
6
+ recursive-include examples *.json *.yaml *.yml *.md
7
+ recursive-include docs *.md *.yaml *.html
8
+ exclude docs/RELEASING.md
9
+ global-exclude __pycache__ *.py[cod]
gramson-0.1.0/Makefile ADDED
@@ -0,0 +1,65 @@
1
+ .DEFAULT_GOAL := help
2
+
3
+ PYTHON ?= python3
4
+ VENV ?= .venv
5
+ VENV_PYTHON := $(VENV)/bin/python
6
+ HOST ?= 127.0.0.1
7
+ PORT ?= 8765
8
+
9
+ .PHONY: help setup setup-release generate example example-bitwise example-external lint lint-python lint-openapi test check build check-dist serve
10
+
11
+ help: ## Show available targets
12
+ @awk 'BEGIN {FS = ":.*## "} /^[a-z-]+:.*## / {printf " %-16s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
13
+
14
+ $(VENV_PYTHON):
15
+ $(PYTHON) -m venv "$(VENV)"
16
+
17
+ setup: $(VENV_PYTHON) ## Create the virtual environment and install the CLI and development dependencies
18
+ "$(VENV_PYTHON)" -m pip install -r requirements-dev.txt
19
+ "$(VENV_PYTHON)" -m pip install -e .
20
+
21
+ setup-release: setup ## Install development and release tooling
22
+ "$(VENV_PYTHON)" -m pip install -r requirements-release.txt
23
+
24
+ generate: ## Generate JSON Schemas from the operator specification
25
+ "$(VENV_PYTHON)" tools/generate_schema.py
26
+
27
+ example: ## Generate and validate the ready-to-run core extension example
28
+ "$(VENV_PYTHON)" -m gramson generate --manifest examples/extension/language.yaml --output-directory build/examples/extension
29
+ "$(VENV_PYTHON)" -m gramson validate examples/extension/expressions/nested.yaml --schema build/examples/extension/expression.schema.yaml
30
+ "$(VENV_PYTHON)" -m gramson validate examples/extension/expressions/nested.json --schema build/examples/extension/expression.schema.yaml
31
+
32
+ example-bitwise: ## Generate and validate the bitwise extension example
33
+ "$(VENV_PYTHON)" -m gramson generate --manifest examples/bitwise/language.yaml --output-directory build/examples/bitwise
34
+ "$(VENV_PYTHON)" -m gramson validate examples/bitwise/expressions/nested.yaml --schema build/examples/bitwise/expression.schema.yaml
35
+ "$(VENV_PYTHON)" -m gramson validate examples/bitwise/expressions/nested.json --schema build/examples/bitwise/expression.schema.yaml
36
+ "$(VENV_PYTHON)" -m gramson validate examples/bitwise/expressions/conversions.yaml --schema build/examples/bitwise/expression.schema.yaml
37
+ "$(VENV_PYTHON)" -m gramson validate examples/bitwise/expressions/conversions.json --schema build/examples/bitwise/expression.schema.yaml
38
+
39
+ example-external: ## Generate and validate an external namespace include
40
+ "$(VENV_PYTHON)" -m gramson generate --manifest examples/external/language.yaml --spec-path examples/external/vendor --output-directory build/examples/external
41
+ "$(VENV_PYTHON)" -m gramson validate examples/external/expressions/nested.yaml --schema build/examples/external/expression.schema.yaml
42
+ "$(VENV_PYTHON)" -m gramson validate examples/external/expressions/nested.json --schema build/examples/external/expression.schema.yaml
43
+
44
+ lint: lint-python lint-openapi ## Run Python and OpenAPI linting
45
+
46
+ lint-python: ## Lint Python code and import ordering with Ruff
47
+ "$(VENV_PYTHON)" -m ruff check .
48
+
49
+ lint-openapi: ## Validate the OpenAPI document and its external references
50
+ "$(VENV_PYTHON)" -m openapi_spec_validator docs/openapi.yaml
51
+
52
+ test: ## Run all tests, including generated-schema freshness checks
53
+ "$(VENV_PYTHON)" -m unittest discover -s tests -v
54
+
55
+ check: lint test ## Run lint and tests without regenerating files
56
+
57
+ build: ## Build a source distribution and a wheel from that source distribution
58
+ "$(VENV_PYTHON)" -m build
59
+
60
+ check-dist: build ## Check package metadata, bundled schemas, and installed CLI
61
+ "$(VENV_PYTHON)" tools/check_distribution.py dist
62
+
63
+ serve: generate ## Generate schemas and serve the Swagger viewer locally
64
+ @printf 'Swagger viewer: http://%s:%s/docs/\n' "$(HOST)" "$(PORT)"
65
+ "$(VENV_PYTHON)" -m http.server "$(PORT)" --bind "$(HOST)"
gramson-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,180 @@
1
+ Metadata-Version: 2.4
2
+ Name: gramson
3
+ Version: 0.1.0
4
+ Summary: Define JSON expression languages declaratively
5
+ Author: Kim Bäckström
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/kbck/gramson
8
+ Project-URL: Documentation, https://github.com/kbck/gramson#readme
9
+ Project-URL: Repository, https://github.com/kbck/gramson
10
+ Project-URL: Issues, https://github.com/kbck/gramson/issues
11
+ Keywords: json-logic,json-schema,expressions,validation,yaml
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Code Generators
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ License-File: THIRD_PARTY_NOTICES.md
26
+ License-File: tests/vendor/jsonlogic/LICENSE
27
+ Requires-Dist: jsonschema<5,>=4.18
28
+ Requires-Dist: PyYAML<7,>=6
29
+ Requires-Dist: referencing<1,>=0.28
30
+ Dynamic: license-file
31
+
32
+ # Gramson
33
+
34
+ **Define JSON expression languages declaratively.**
35
+
36
+ Gramson compiles composable YAML operator definitions into recursive JSON Schema
37
+ grammars. Its CLI generates languages and validates JSON or YAML expressions,
38
+ with readable error locations and no network requests during validation.
39
+
40
+ ## Install and validate
41
+
42
+ Requires Python 3.10 or newer. Install in a virtual environment:
43
+
44
+ ```sh
45
+ python -m pip install gramson
46
+ gramson validate expression.json
47
+ gramson validate expression.yaml
48
+ ```
49
+
50
+ For example, `expression.yaml` can contain:
51
+
52
+ ```yaml
53
+ if:
54
+ - '>':
55
+ - var: age
56
+ - 18
57
+ - adult
58
+ - minor
59
+ ```
60
+
61
+ Read one expression from stdin:
62
+
63
+ ```sh
64
+ printf '%s\n' '{"var":"price"}' | gramson validate -
65
+ printf '%s\n' 'var: price' | gramson validate --format yaml -
66
+ ```
67
+
68
+ Files ending in `.yaml` or `.yml` are read as YAML; other files and stdin default
69
+ to JSON. Use `--format json` or `--format yaml` to override detection. Each input
70
+ contains one expression, without an API request envelope. YAML values must be
71
+ representable as JSON: duplicate or non-string keys, non-finite numbers,
72
+ timestamps, and cyclic aliases are rejected. Quote dates to use them as strings.
73
+
74
+ Exit codes are `0` for valid syntax, `1` for an invalid expression, and `2` for
75
+ input, schema, or command usage errors. `python -m gramson validate ...` is also supported.
76
+
77
+ ## Generate and extend a language
78
+
79
+ The [ready-to-run extension example](https://github.com/kbck/gramson/tree/main/examples/extension)
80
+ contains manifests, a custom operator, JSON/YAML expressions, and instructions.
81
+ It is also included in the source distribution; run `make setup` and `make example`
82
+ from its repository or source-distribution root.
83
+ The [bitwise extension](https://github.com/kbck/gramson/tree/main/examples/bitwise)
84
+ adds `&`, `|`, `^`, `~`, `<<`, `>>`, `hexToInt`, and `intToHex`;
85
+ run it with `make example-bitwise`.
86
+ Its reusable declarations are bundled in Gramson and can be selected directly:
87
+
88
+ ```yaml
89
+ include:
90
+ - gramson:core
91
+ - gramson:bitwise
92
+ ```
93
+
94
+ No declaration copying is needed. Add `operatorDirectories` for local groups,
95
+ or include only `gramson:bitwise` to select it without core. Duplicate includes,
96
+ unknown names, and operator, definition-name, or output-path collisions are errors.
97
+
98
+ User-owned libraries can use their own namespaces:
99
+
100
+ ```yaml
101
+ include:
102
+ - gramson:core
103
+ - mystuff:myops
104
+ ```
105
+
106
+ ```sh
107
+ gramson generate --manifest language.yaml --spec-path ./vendor --output-directory generated
108
+ ```
109
+
110
+ This reads operator declarations from `vendor/mystuff/myops/` recursively.
111
+ Repeat `--spec-path` for multiple libraries; paths are relative to the command's
112
+ working directory. `gramson:` is reserved for bundled definitions. Unknown or
113
+ ambiguous includes fail, and namespace labels do not prefix operator keys.
114
+ Generated schemas remain self-contained and validate without the source library.
115
+ See the [external library example](https://github.com/kbck/gramson/tree/main/examples/external),
116
+ also runnable with `make example-external` from the source distribution.
117
+
118
+ `gramson generate --output-directory generated` writes the bundled core grammar
119
+ as a self-contained directory. For a custom language, create a manifest:
120
+
121
+ ```yaml
122
+ # my-language/language.yaml
123
+ include:
124
+ - gramson:core
125
+ operatorDirectories:
126
+ - custom
127
+ ```
128
+
129
+ Add declarations in `my-language/custom/wrapping.yaml`:
130
+
131
+ ```yaml
132
+ wrap:
133
+ schemaName: wrapper
134
+ title: Wrapper
135
+ summary: Wrap one expression.
136
+ argumentKind: expression
137
+ minArgs: 1
138
+ maxArgs: 1
139
+ ```
140
+
141
+ ```sh
142
+ gramson generate --manifest my-language/language.yaml --output-directory generated
143
+ gramson validate expression.yaml --schema generated/expression.schema.yaml
144
+ ```
145
+
146
+ Generated output includes core and custom schemas, shared definitions, and one
147
+ expression entry point; operators can nest across groups. Keep the output
148
+ directory together when moving it. Validation against `--schema` uses those
149
+ files offline and does not depend on the installed core language.
150
+
151
+ Without `include`, a manifest selects only local directories.
152
+ `include: [gramson:core]` alone selects just core. Include order does not give
153
+ precedence: duplicate operator keys, definition names, or output paths fail the
154
+ whole generation. Pin the Gramson version for reproducible bundled declarations.
155
+ Custom declarations define syntax; they do not implement evaluation.
156
+
157
+ ## Compatibility and contents
158
+
159
+ The included JSON Logic syntax profile covers all 34 documented operators plus
160
+ the `?:` alias. All 278 expressions in the pinned upstream corpus pass syntax
161
+ validation. Gramson applies stricter argument counts and object-shape rules than
162
+ the reference interpreter and validates every branch. There is no evaluator;
163
+ runtime equivalence is not tested.
164
+
165
+ The wheel includes the generated schemas under `gramson.schemas`, preserving
166
+ relative references for offline use. They can be accessed with
167
+ `importlib.resources.files("gramson.schemas")`. Core and optional extension declarations are bundled
168
+ under `gramson.specs`, and the generator is included in the installed package.
169
+ The source distribution also contains tests and user documentation.
170
+
171
+ See the [repository and development guide](https://github.com/kbck/gramson#readme),
172
+ [operator specification](https://github.com/kbck/gramson/blob/main/spec/README.md),
173
+ and [issue tracker](https://github.com/kbck/gramson/issues).
174
+
175
+ ## License and acknowledgements
176
+
177
+ Gramson is licensed under MIT. Its included expression language builds on
178
+ [JSON Logic](https://jsonlogic.com/), created by Jeremy Wadhams. The vendored
179
+ upstream tests retain their original MIT license and attribution; see the
180
+ [third-party notices](https://github.com/kbck/gramson/blob/main/THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,111 @@
1
+ # Gramson
2
+
3
+ **Define operators once. Generate the grammar that validates your JSON expressions.**
4
+
5
+ Adding operators to a JSON expression language means keeping its syntax rules
6
+ and validation in sync. Gramson compiles YAML operator declarations into a
7
+ recursive JSON Schema grammar, so adding an operator or changing its arguments
8
+ doesn't require hand-editing the validation schema.
9
+
10
+ ## Why Gramson?
11
+
12
+ JSON Schema can already validate recursive expressions. Gramson generates the
13
+ operator objects, argument-count constraints, shorthand forms, and references
14
+ from your declarations. JSON Logic supplies the bundled starting profile;
15
+ you can extend it or define an independent language.
16
+
17
+ **Operator libraries become composable grammar modules.** Include groups from
18
+ different libraries, and their operators can nest inside one another. The
19
+ combined grammar is generated from the selected definitions and works with
20
+ standard Draft 2020-12 JSON Schema validators.
21
+
22
+ Gramson is a Python library and CLI. It defines and validates syntax; it does
23
+ not evaluate expressions.
24
+
25
+ ## Example
26
+
27
+ Declare an operator that takes exactly one expression:
28
+
29
+ ```yaml
30
+ wrap:
31
+ argumentKind: expression
32
+ minArgs: 1
33
+ maxArgs: 1
34
+ ```
35
+
36
+ Combine it with the bundled core language, and the generated schema accepts:
37
+
38
+ ```json
39
+ {"wrap": [{"+": [1, 2]}]}
40
+ ```
41
+
42
+ It rejects `{"wrap": [1, 2]}` because `wrap` takes one argument. Recursive
43
+ references let your operators nest inside core operators, and vice versa.
44
+
45
+ ## Try it
46
+
47
+ Requires Python 3.10 or newer. From a checkout:
48
+
49
+ ```sh
50
+ make setup
51
+ make example
52
+ ```
53
+
54
+ This installs the CLI, generates a language with `wrap`, and validates the
55
+ included JSON and YAML expressions. The [complete example](examples/extension/README.md)
56
+ contains the manifest, declarations, and expressions ready to edit.
57
+
58
+ For your own files, the workflow is:
59
+
60
+ ```sh
61
+ . .venv/bin/activate
62
+ gramson generate --manifest language.yaml --output-directory generated
63
+ gramson validate expression.yaml --schema generated/expression.schema.yaml
64
+ ```
65
+
66
+ Generated output is self-contained and validates offline. Without `--schema`,
67
+ validation uses the bundled core grammar. See the [usage guide](docs/USAGE.md)
68
+ for input formats, stdin, exit codes, and custom languages.
69
+
70
+ ## Compose a language
71
+
72
+ Select bundled groups and local declarations in a manifest:
73
+
74
+ ```yaml
75
+ include:
76
+ - gramson:core
77
+ - gramson:bitwise
78
+ operatorDirectories:
79
+ - custom
80
+ ```
81
+
82
+ - **Core:** a JSON Logic syntax profile covering 34 documented operators plus
83
+ `?:`. All 278 expressions in the pinned upstream corpus pass syntax validation.
84
+ Structural rules are stricter than the reference interpreter; runtime
85
+ equivalence is untested.
86
+ - **Bitwise:** six bitwise operators plus `hexToInt` and `intToHex` conversion
87
+ forms. Try `make example-bitwise`.
88
+ - **Your libraries:** include names such as `mystuff:myops` with explicit
89
+ `--spec-path` search roots. Try `make example-external`.
90
+
91
+ Include order gives no precedence: duplicate operator keys, definition names,
92
+ or output paths fail generation. The [specification guide](spec/README.md)
93
+ explains declarations and include resolution.
94
+
95
+ ## Documentation
96
+
97
+ - [Usage and CLI](docs/USAGE.md)
98
+ - [Operator specification and manifest format](spec/README.md)
99
+ - [Scope, compatibility boundaries, and open questions](docs/DESIGN.md)
100
+ - [Development commands and repository layout](docs/DEVELOPMENT.md)
101
+ - [Swagger schema viewer](docs/README.md)
102
+
103
+ To work on Gramson, run `make check` for Ruff, OpenAPI validation, and tests.
104
+ Run `make help` for all targets.
105
+
106
+ ## License and acknowledgements
107
+
108
+ [MIT](LICENSE). The included JSON Logic profile builds on
109
+ [JSON Logic](https://jsonlogic.com/), created by Jeremy Wadhams. Its shared test
110
+ corpus is vendored with the original MIT license and attribution; see
111
+ [third-party notices](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,15 @@
1
+ # Third-party notices
2
+
3
+ ## JSON Logic shared tests
4
+
5
+ The files `tests/vendor/jsonlogic/tests.json` and
6
+ `tests/vendor/jsonlogic/LICENSE` are copied verbatim from the upstream JSON Logic
7
+ project maintained by Jeremy Wadhams.
8
+
9
+ Copyright (c) 2015 Jeremy Wadhams. Licensed under the MIT License; the complete
10
+ copyright, permission, and warranty notice is included in
11
+ [tests/vendor/jsonlogic/LICENSE](tests/vendor/jsonlogic/LICENSE).
12
+
13
+ The [snapshot metadata](tests/vendor/jsonlogic/snapshot.json) identifies the
14
+ immutable upstream revisions, source URLs, and SHA-256 checksums. See the
15
+ [vendoring guide](tests/vendor/jsonlogic/README.md) for usage and update rules.
@@ -0,0 +1,55 @@
1
+ # Scope and design decisions
2
+
3
+ ## Scope and decisions
4
+
5
+
6
+ - Accept JSON scalar literals and recursive arrays of expressions.
7
+ - Represent each operation as a closed object with exactly one registered key.
8
+ - Support data access, conditionals, Boolean logic, comparisons, arithmetic,
9
+ collections, strings, and logging syntax.
10
+ - Accept variable defaults, numeric and computed keys, unary shorthand, and
11
+ the documented arity profile.
12
+ - Reject unknown operators and arbitrary object literals throughout expressions,
13
+ including inside arrays, defaults, and unselected branches.
14
+
15
+ This specifies structural acceptance. It does not implement evaluation or
16
+ semantic typing. For example, `{"+": [true, "2", null]}` and
17
+ `{"map": [true, "body"]}` pass syntax validation without promising meaningful
18
+ evaluation. The profile constrains arities rather than accepting every malformed
19
+ call that a permissive interpreter might process.
20
+
21
+ `if` and its `?:` alias accept condition/result pairs with an optional final fallback. The agreed
22
+ runtime result is `null` when no condition matches and no fallback is supplied;
23
+ there is no evaluator yet to execute that rule.
24
+ Empty argument lists are accepted and yield `null` in JSON Logic. A single
25
+ argument is a fallback expression; non-array shorthand is also accepted.
26
+
27
+ Results are data rather than expressions. The hand-written
28
+ [JSON-value schema](json-value.schema.yaml) accepts scalars, recursive
29
+ arrays, and arbitrary objects. It reuses `scalarLiteral` from the generated shared schema
30
+ but defines its own recursive containers so result objects are never treated as
31
+ operator calls.
32
+
33
+ ## Open design questions
34
+
35
+
36
+ - **Semantic typing:** Should a separate phase check operand and result types?
37
+ How would it learn variable types and handle null or missing values?
38
+ - **Explicit conversions:** This remains the preferred direction. Unary `+` and
39
+ `!!` are accepted syntax, but conversion failures and implicit coercions
40
+ remain undecided.
41
+ - **Named constants:** Are they needed, and how should they be represented,
42
+ scoped, and distinguished from external data?
43
+ - **Custom operator extensions:** The registry describes build-time syntax.
44
+ Runtime operator registration, scoping, and versioning remain unspecified.
45
+ - **Evaluation and compatibility:** Lookup, truthiness, arithmetic, equality,
46
+ collection scope, short-circuiting, and errors require decisions. The
47
+ no-fallback `if` result is settled as `null`.
48
+
49
+ ## Next steps
50
+
51
+
52
+ Settle semantic typing, conversions, and runtime compatibility before building
53
+ an evaluator. For each syntax change, update the relevant operator file, regenerate the
54
+ schemas, and add accepted and rejected examples.
55
+
@@ -0,0 +1,111 @@
1
+ # Developing Gramson
2
+
3
+ ## Files
4
+
5
+
6
+ - `spec/language.yaml`: selects the operator directories included in the language.
7
+ - `spec/core/*.yaml`: operator syntax, arities, names, titles, and summaries,
8
+ grouped into data, logic, comparison, arithmetic, collection, string, and debugging.
9
+ Longer descriptions are optional.
10
+ - `spec/extensions/*.yaml`: reusable optional extensions, selected explicitly by
11
+ manifests through `include` (currently `gramson:bitwise`).
12
+ - `gramson/generation.py`: loads and composes specifications and generates schemas.
13
+ - `tools/generate_schema.py`: repository generation entry point used by `make generate`.
14
+ - `gramson/cli.py`: generates grammars and validates JSON or YAML expressions.
15
+ - `pyproject.toml`: package metadata, runtime dependencies, and the `gramson` command.
16
+ - `schema/expression.schema.yaml`: generated language entry point.
17
+ - `schema/core/*.schema.yaml`: generated named operator definitions, mirroring
18
+ the source directories and file base names.
19
+ - `schema/shared.schema.yaml`: generated shared definitions such as `scalarLiteral`.
20
+ - `docs/json-value.schema.yaml`: hand-written result-data grammar.
21
+ - `examples/valid.json` and `examples/invalid.json`: accepted and rejected
22
+ expressions; only each entry's `expression` is validated.
23
+ - `tests/test_validation.py`: metaschema and example validation.
24
+ - `tests/test_jsonlogic.py`: offline syntax compatibility checks against the
25
+ pinned upstream [JSON Logic test corpus](../tests/vendor/jsonlogic/README.md),
26
+ with its MIT license, provenance, checksums, and compatibility expectations.
27
+ - `tests/test_generation.py`: generation freshness, operator coverage, arities,
28
+ shorthand, documentation, and registry validation.
29
+ - `tests/test_language.py`: directory selection, deterministic composition,
30
+ collision diagnostics, mirrored output, and cross-group recursion.
31
+ - `tests/test_openapi.py`: external references, request validation, and result
32
+ validation against the hand-written API contract.
33
+ - `docs/openapi.yaml`: hand-written placeholder `POST /evaluate` specification;
34
+ its only schema components reference `expression` and `jsonValue`.
35
+ - `docs/index.html`: Swagger viewer; see [viewing instructions](README.md).
36
+ - `requirements-dev.txt`: generation, validation, YAML-reading, and Ruff linting dependencies.
37
+
38
+ ## Layout and composition
39
+
40
+
41
+ ```text
42
+ spec/ schema/
43
+ language.yaml expression.schema.yaml
44
+ shared.schema.yaml
45
+ core/ core/
46
+ arithmetic.yaml arithmetic.schema.yaml
47
+ logic.yaml logic.schema.yaml
48
+ ... ...
49
+ ```
50
+
51
+ The repository manifest currently enables only its local `core`. Additional directories can be
52
+ enabled explicitly; operator sources are scanned recursively and sorted.
53
+ Duplicate operator keys or `schemaName` values are errors with both source
54
+ paths reported. Each group references the root expression grammar, allowing
55
+ nested expressions from every enabled group. See the specification guide for
56
+ manifest rules and custom output locations.
57
+
58
+ ## Generate and validate
59
+
60
+
61
+ Requires Python 3.10 or newer. From the repository root:
62
+
63
+ ```sh
64
+ make setup
65
+ make generate
66
+ make check
67
+ ```
68
+
69
+ Run `make` or `make help` to list targets:
70
+
71
+ | Target | Purpose |
72
+ | --- | --- |
73
+ | `setup` | Create `.venv` and install the CLI and development dependencies. |
74
+ | `generate` | Generate the expression, shared, and operator JSON Schemas. |
75
+ | `example` | Generate and validate the included core extension example. |
76
+ | `example-bitwise` | Generate and validate the bitwise extension example. |
77
+ | `example-external` | Generate and validate a user-owned namespace include. |
78
+ | `lint` | Run Python and OpenAPI linting. |
79
+ | `lint-python` | Check Python code and import ordering with Ruff. |
80
+ | `lint-openapi` | Validate the hand-written OpenAPI document and external references with [openapi-spec-validator](https://openapi-spec-validator.readthedocs.io/en/stable/cli.html). |
81
+ | `test` | Run all tests, including schema validation and generation freshness. |
82
+ | `check` | Run lint and tests without rewriting generated files. |
83
+ | `setup-release` | Install development and release tooling. |
84
+ | `build` | Build a source archive and a wheel from that source archive. |
85
+ | `check-dist` | Build and check metadata, bundled schemas, and the installed CLI. |
86
+ | `serve` | Regenerate schemas and serve the Swagger viewer at `http://127.0.0.1:8765/docs/`. |
87
+
88
+ Override `PYTHON` or `VENV` for setup, or `HOST` and `PORT` for the viewer,
89
+ for example `make serve PORT=8000`. Run `make setup` before other targets.
90
+ The OpenAPI wrapper and JSON-value schema remain hand-written; `make generate`
91
+ only rebuilds the expression grammar. `make check` fails when generated schemas
92
+ are stale, so regenerate and commit them after changing operator sources.
93
+
94
+ [GitHub Actions](../.github/workflows/check.yml) runs `make check` on every push and
95
+ pull request with Python 3.10 and 3.14. CI checks the committed schemas without
96
+ regenerating them.
97
+ It also builds and verifies the wheel and source distribution. The
98
+ [release guide](RELEASING.md) documents local checks and the PyPI Trusted
99
+ Publishing setup. Publishing a matching GitHub release triggers the separate
100
+ publication workflow; routine pushes and pull requests only build and check.
101
+
102
+ Python linting uses Ruff, configured in `pyproject.toml` for Python 3.10 with
103
+ error, unused-code, and import-order checks. `make lint-python` checks without
104
+ rewriting files. To apply safe fixes locally, run `.venv/bin/python -m ruff check . --fix`.
105
+ Ruff is a development dependency; the installed CLI does not require it.
106
+
107
+ Generation uses PyYAML to read and write YAML. Tests use local schemas and bundled
108
+ metaschema support, with no remote schema fetches. The expression, shared, and grouped operator schemas are
109
+ generated; edit the OpenAPI and JSON-value schemas directly when their contracts
110
+ change. Tests assert syntax and data shape, not evaluation results.
111
+