Conversation
Either side of a comparison in a where string may be an expression, read as an expression is: macros and named expressions expand, every operator keeps its rule, and a variable or a dual is refused. Resolution types it as `ArithmeticComparisonNode` over the core syntax tree for the spec-side readers; lowering rebuilds every mask with `ExpressionComparisonNode` over program expressions, so a program's masks are program vocabulary throughout. The expression form stands aside for the plain shapes, so `p > 0` keeps its node. Docs sentence lengths (n / median / over 25): expressions.md 139 / 16 / 27, reading.md 68 / 15 / 15. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
FBumann
marked this pull request as ready for review
September 15, 2026 08:44
FBumann
added this pull request to stack #472
September 15, 2026 08:48
brynpickering
approved these changes
Sep 15, 2026
brynpickering
left a comment
Contributor
There was a problem hiding this comment.
Thanks for opening this. Definitely needed!
| side is read exactly as an [expression](#expressions) is, so a macro and a | ||
| named expression expand into it and every operator keeps its own rule. Two | ||
| things an expression may carry are refused here, because a mask is built before | ||
| either exists: a variable, and a `dual()`. |
Contributor
There was a problem hiding this comment.
and other expressions (at least insofar as those other expressions include variables or duals)?
Comment on lines
+252
to
+256
| A case `when:` that compares expressions cannot be proved apart from its | ||
| neighbours before the data arrives, so it is refused there with the rewrite: | ||
| compare one parameter against a literal, or precompute the test as a boolean | ||
| parameter. | ||
|
|
Contributor
There was a problem hiding this comment.
I don't really understand this sentence at all.
Contributor
Author
There was a problem hiding this comment.
when is the thing that Cases operates on.
So each when separates an expression.
To enable static analysis of the when separations, we disallow complex expressions in when.
This might be feasible, but im not sure if it is.
…pare expressions (#476)
Brings the branch up to 0b4f046, which carries #437's relations rename and #449's gallery renames. Deliberately 0b4f046 rather than main: main also carries #474, which #481 reverts, and merging it here would resurrect it. Seven files conflicted. The renames main made are taken, and this branch's new nodes are kept alongside them: - The frame-check message keeps this branch's `leaf` phrase, which the two expression-comparison nodes need because they carry no name, with main's wording and `where-relation` spelling for the four named cases. - `_comparison` takes main's dotted-column body, with this branch's `expressions:` check in front of it. - `_expression_comparison` and main's `_relation_column` are both kept. - `LookupNode` is `RelationNode`, and a translation's `partition` is now a `Walk`, so `names_read` reads `.name` off it. - The new cases spell `shift`/`sum_back` with `along=` and `window=`. The generated schema, goldens and pages are regenerated, not hand-merged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017VApqcmBKLXtKTmk3ajmtK
FBumann
pushed a commit
that referenced
this pull request
Sep 15, 2026
Brings this branch onto #469 as rebuilt on the alpha.90 release, so it picks up #437's relations rename and #449's gallery renames. Nine files conflicted, and three more merged cleanly while still written in the old vocabulary, which was the larger half of the work: - The typesetting union this branch adds was named `RelationNode`, which main now uses for a resolved `by=`. The alias is `AlignedComparison`, and `_relation` reads a relation column through `_value_read` and a position group through `_position_group`, as main's `_predicate` does. - `_comparison` keeps main's dotted-column body and this branch's parameter pair, which is taken only where neither side names a column. - `_parameter_pair_error` and main's `_relation_pair_error` are both kept. - `examples/commitment.yaml` assumed `p_min <= p_max`, which #449 renamed to `min_output <= capacity`. - The new cases spell `shift`/`sum_back` with `along=` and `window=`. - The expressions page said two parameters cannot be compared, which this branch makes false; it now states both pair forms. The generated schema, goldens and pages are regenerated, not hand-merged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017VApqcmBKLXtKTmk3ajmtK
Relations replaced lookups upstream, so the arithmetic comparison lands on the new plan: the `Lookup*` predicate nodes are `Relation*`, `_names_under` reads a partition's `Walk` rather than a name, and the golden model's `ramped` where says `along=`. `_comparison` keeps main's relation-column reading and takes the expression path first, as before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pdMgEVkGBfh1f2AyiCSKA
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014pdMgEVkGBfh1f2AyiCSKA
This was referenced Sep 18, 2026
Contributor
Author
|
Superseeded by #566 |
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.
Note
The following content was generated by AI.
Either side of a comparison in a where string may now be arithmetic over parameters:
p_min <= 0.5 * p_max,sum(p_max, over=generator) >= peak,p_max <= at(bus_cap, by=bus_of), a macro, a named expression. It applies to everywhere: a variable's, a constraint's, and theassumptions:block of #465, which now stacks on this. Replaces #466.What this changes
Grammar, resolution, the two vocabularies, rendering
Grammar. The where grammar's comparison atom gains
expression COMPARATOR expression, with the expression parser's arithmetic element (ARITHMETIC, now exposed) on each side. The three comparison forms are matched longest-first, sop > 2 * qis not cut short atp > 2; the expression form stands aside for the plain shapes and forposition(...), sop > 0keeps the node its dtype rule is written for. A side is held to the same nesting depth as an expression, measured on the where text.Resolution. A side is expanded (macros, named expressions), typed, degree-checked and dim-checked exactly as an expression is; the dims stamped on the node are every dim either side carries. Two things an expression may carry are refused here: a variable and a
dual().Namespacenow carries the schema, which those checks need. A plain-form comparison that names anexpressions:entry on either side takes the expression path.Two vocabularies. The resolved tree holds
ArithmeticComparisonNodeover the core syntax tree, which the typesetter, the dim rules and the exclusivity check read.lower_programrebuilds every mask, on variables, constraints and case regions, withExpressionComparisonNodeover program expressions in its place, so a program's masks are program vocabulary throughout. Both are in the closedWhereNodeunion; the docstring on the first says a program never carries it.Meaning. A comparison of expressions holds at every coordinate of the dims either side carries, and is held to the frame it sits in like any mask. A side with no value at a coordinate compares false, as a null does in every other comparison; under a summing operator the absent term is one fewer. A
shiftnames itsedge=as it does everywhere, and aposition()term keeps the vacated row out (the reference shows the example).Not decided. A case
when:that compares expressions is refused as undecidable before the data arrives, with the rewrite, the way an ordered lookup pair is.Rendering. One branch in the walk, since it already renders arithmetic.
names_readon a mask now includes the lookup a grouping or pullback joins through and the parameter a named offset or width is read from, which an engine has to bind.Not done here.
max,minandcountare new primitives, taxed aslimits.mdsays. lpspec's mask evaluation gains an expression evaluator in its own PR.Verified
uvvenv, Python 3.12, sincepixiis not installable in this environment:pytest -n auto: 1233 passed, 10 skipped; the fivetest_docs.pyhook tests that needmkdocsdeselected, as they fail onmainhere too.ruff check,ruff format --check,pyrefly check,prettier --check docs: clean.typstpackage.compile-tex,docs-build --strict,reuse,typos,taplo,zizmor. The same change on feat(language): a where may compare arithmetic over parameters, so an assumption can say what a formula has to satisfy #466's stacked branch passed all of CI, including those.Mutation table
Taken on the stacked branch of #466, which carries this change verbatim on top of #465; each guard deleted in turn, the suite run, the file restored from a copy and the tree checked clean.
test_a_where_is_one_resolved_predicate_with_every_literal_folded[…], the gallery pages, the parser tests[a-variable-inside-arithmetic],test_a_bound_or_where_cannot_name_an_expression[where][a-dual-inside-arithmetic][a-named-expression-on-the-left],[…-right]test_a_comparison_of_expressions_lowers_to_program_expressions_on_both_sides, the notation pagetest_a_case_comparing_expressions_is_refused_as_undecidabletest_a_comparison_of_expressions_lowers_to_program_expressions_on_both_sidesCoverage moved
test_a_bound_or_where_cannot_name_an_expression[where]asserted that a where naming anexpressions:entry fails to resolve; the entry is now read as arithmetic, and the case asserts the variable refusal that body earns instead.ExpressionComparisonNodejoins the census's list of nodes the walk never meets, with the walk's guard on it exempted from the line census.🤖 Generated with Claude Code
https://claude.ai/code/session_013HceuCYNepeQX8SdZtiMf1
Generated by Claude Code