Skip to content

Decode && / || boolean operators when re-emitting from BNG-XML#76

Merged
jrfaeder merged 4 commits intoRuleWorld:mainfrom
wshlavacek:modelapi-decode-xml-boolean-ops
May 11, 2026
Merged

Decode && / || boolean operators when re-emitting from BNG-XML#76
jrfaeder merged 4 commits intoRuleWorld:mainfrom
wshlavacek:modelapi-decode-xml-boolean-ops

Conversation

@wshlavacek
Copy link
Copy Markdown
Contributor

Summary

BNG2.pl's <Expression> serializer rewrites the binary operators && and || as the function-call-shaped strings (L)and(R) and (L)or(R) (see Perl2/Expression.pm: '&&' => 'and'). When bionetgen.modelapi reads <Expression> verbatim and re-emits the function body into a regenerated .bngl, BNG2.pl's BNGL parser sees and(...) as a function call and aborts:

Missing end parentheses ... at and(t>=0))

This breaks any round-trip workflow (parse a BNGL → regenerate it → re-run with BNG2.pl) for models that use boolean operators inside function bodies. Smallest repro is a function like:

toggle = if((plusBafA1==1) && (t>=0), 0, 1)

After XML round-trip this becomes if((plusBafA1==1)and(t>=0), 0, 1) which BNG2.pl rejects.

Fix

In bionetgen/modelapi/xmlparsers.py, add a regex pass that maps )and() && ( and )or() || ( before storing the function expression. The match is intentionally anchored on the close-paren of the left operand because BNG2.pl always wraps both operands in parens for these forms — so )and( / )or( only ever appear as the boolean-operator encoding and never as the tail of a user-defined identifier (e.g. random(x)) or a literal function call.

Test plan

  • Existing CI passes
  • Round-trip a model with && / || in a function body: parse → write_model → BNG2.pl simulate
  • Verify random(x) + myop(y) is preserved verbatim (no spurious rewrites of )and(-shaped substrings that aren't actually boolean ops — there shouldn't be any, but worth checking)

BNG2.pl's <Expression> serializer rewrites the binary operators ``&&`` and
``||`` as the function-call-shaped strings ``(L)and(R)`` and ``(L)or(R)``
(see Perl2/Expression.pm: '&&' => 'and'). Reading <Expression> verbatim
and re-emitting it into a regenerated .bngl file confuses BNG2.pl's BNGL
parser, which sees ``and(...)`` as a function call and aborts with
"Missing end parentheses ... at and(...)".

Fix: in xmlparsers, run a regex pass that maps ``)and(`` → ``) && (`` and
``)or(`` → ``) || (`` before storing the function expression. The match
is anchored on the close-paren of the left operand because BNG2.pl always
wraps both operands in parens for these forms — so ``)and(`` / ``)or(``
only ever appear as the boolean-operator encoding and never as the
suffix of a user identifier or a literal function call.
jrfaeder added 3 commits May 11, 2026 12:06
Resolved conflict by integrating boolean operator decoding with the new
_resolve_expression() method introduced in main.
@jrfaeder jrfaeder merged commit 784477b into RuleWorld:main May 11, 2026
0 of 17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants