Skip to content

This site describes solve-engine as it is on main: 2.43.0, which npm does not have yet. npm installs 2.40.0, so a page may show an answer that version does not give yet.

CONDITIONALS_PACKAGE

const CONDITIONALS_PACKAGE: IEnginePackage;

Defined in: packages/engine/src/packages/conditionals/ConditionalsPackage.ts:60

Comparisons (==, !=, <, >, <=, >=), boolean logic (true/ false, and/or/&&/||), and if <cond> then <val> else <val> eager-ternary conditionals.

The and/or split is deliberate, not an oversight: this package does not register “and” at all. The word lexes as its own token, AND_CONJ (en.ts: and: "AND_CONJ", see the comment on it in lexer/Token.ts), and the arithmetic package registers it as an infix OpCode.ADD, because “5 and 3” is 8. Which meaning applies is a property of the operands, so OpCode.ADD’s VM handler special-cases Boolean + Boolean as the conjunction (see vm/VM.ts). “or”/”&&”/”||” have no such collision and are handled here via LogicalParselet.

GROUPING: AND_CONJ binds at BindingPower.Conjunction (parser/BindingPower.ts), looser than Conditional, so an unparenthesised X >= Y and Z < W parses as (X >= Y) and (Z < W), the same grouping && gets at LogicalAnd. Both comparisons produce booleans, so the ADD handler answers the conjunction. Between two plain numbers the word is still addition (“2 and 3” is 5), and with a number on one side and a comparison on the other it adds the boolean as 1 or 0 (“2 and 3 > 1” is 3). Both readings are pinned by hardening/ArithmeticConditionals.spec.ts and the mathphrases AndAsListSeparator.spec.ts.

TRIGGER-WORD COLLISION: not (#751) is ordinary English and was a free name, so it is not a lexer keyword. The normaliser fuses it to NOT only where it stands in front of a value (the start of a line, or after if, then, else, a bracket, a comma, and/or or a comparison) and a condition follows it. not = 3 and not + 1 keep the variable, and a sentence that starts with the word stays a non-answer. See NotNormalizerRule.ts. A prefix ! needs no such care: after a value it is the factorial (an infix parselet in the function package), and anywhere else it was an error.

SCOPE DECISION: SoulverCore-style postfix Y if X / Y unless X (a ternary with no explicit else-branch) is deliberately NOT implemented. This VM’s Value has no “empty”/“void” representation for the false-branch case (every expression must produce a concrete typed result), building it properly would mean adding a new sentinel ValueType and deciding how every consumer (formatting, DAG propagation, UOM/arithmetic ops) treats it, which is a bigger call than this package should make implicitly. if X then Y else Z (both branches required) covers the same need unambiguously today.