Skip to content

produces when drops parentheses when printed, and its precedence disagrees with a policy condition #83

Description

@woksin

Found while fixing #59. The policy condition is not the only place a printed condition loses its grouping — produces when has the same defect. But fixing it the same way runs into a second, larger problem, which is why this is filed rather than fixed.

Defect 1 — the printer drops parentheses

ConditionParser accepts parentheses; ScreenplaySyntaxText.Condition (Printing/ScreenplaySyntaxText.cs:70) never emits them:

LogicalConditionSyntax logical => $"{Condition(logical.Left)} {Logical(logical.Operator)} {Condition(logical.Right)}",

Verified with a throwaway spec:

SOURCE:   produces when (a == "1" or b == "2") and c == "3"
PRINTED:  produces when a == "1" or b == "2" and c == "3"
ORIGINAL: ((aEqual Or bEqual) And cEqual)
REPARSED: (aEqual Or (bEqual And cEqual))

Same class as #59: the round trip silently changes meaning, and printing is documented as the inverse of compiling.

Defect 2 — the two condition languages disagree about precedence

This is the part that needs a ruling rather than a fix.

ConditionParser (produces when) implements conventional and-over-or precedence — ParseOrParseAndParsePrimary, Parsing/ConditionParser.cs:36-70.

PolicyParser (policy … require) has no precedence at all — a single flat left-associative loop over both operators, Parsing/PolicyParser.cs:79-95.

So the same text parses to different trees depending on which construct it appears in:

a or b and c

  in produces when  ->  a or (b and c)     (and binds tighter)
  in a policy       ->  (a or b) and c     (strictly left to right)

Two condition languages, one language. A reader who learns one is actively misled by the other, and a consumer implementing against one gets the other wrong.

Why this is not just "fix the printer"

The #59 fix took the position that a policy condition has no precedence and parentheses are the only grouping — that is now stated in grammar.md, policies.md and on the printer itself, and the printer emits parentheses wherever a flat left-to-right read would not reproduce the tree.

Applying the same treatment to produces when means either:

  1. Print parentheses against the existing precedence — cements a conventional precedence-based expression grammar as part of the language, or
  2. Remove precedence from ConditionParser to match policies — consistent, but silently rebinds every existing produces when that mixes and and or, which is the one thing Printer drops parentheses in a policy condition, changing who the policy admits #59 was careful not to do.

Option 1 collides directly with the design constraint under discussion in #81"we lean towards the language not feeling like other languages." A precedence table is exactly what every other language has. Option 2 is a breaking semantic change to shipped documents.

That is a product-owner call about what the language is, not a printer bug to quietly fix, so #59 deliberately left produces when untouched.

Suggested direction

Decide #81 first. If the ruling is statements-over-expressions, option 2 becomes the coherent end state and needs a migration story for the affected documents; if precedence is accepted as part of the language, option 1 is right and the two parsers should be unified so there is one condition grammar rather than two.

Either way the outcome should be one condition language, and the chosen precedence rule stated in grammar.md.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions