Skip to content

Add conditional expressions, truthy coalescing, compound assignment and discard - #32

Draft
Leitwolf11 wants to merge 1 commit into
mainfrom
feature/conditional-expressions
Draft

Leitwolf11 wants to merge 1 commit into
mainfrom
feature/conditional-expressions

Conversation

@Leitwolf11

Copy link
Copy Markdown
Contributor

Summary

Adds four Spec forms that the compiler did not accept (Spec/Language/Operators.vxs §15–18, Decls.vxs §33):

  • condition ? first : second — exactly one result is evaluated.
  • left ?: fallback (also left ? : fallback) — keeps a left value that is true in Boolean context; the left operand is evaluated once.
  • Compound assignment statements += -= *= /= //= %= **= <<= >>= &= ^= |=, including in for update lists.
  • The discard statement _ = value;.

?? and ??= are now lexed as their own tokens and rejected with VXP0030 / VXP0031 until nullable types exist.

How it works

  • Frontend: four new AST nodes carried through every pass. Wildcard fallbacks that would have silently treated a conditional as call-free were replaced by explicit cases.
  • Core: a lazy CoreConditional expression in the Haskell and native models, both verifiers and both wire codecs. Core wire is now v8 (expression tag 6). CorePrep, Xpp and Xmm are unchanged: the expression becomes control flow before CorePrep.
  • Optimizer: effect inference, integer facts, constant folding, liveness and inlining treat the arms as alternative paths.
  • CorePrep: a branch over one result slot, seeded before the branch and assigned in each arm block — the same pattern as short-circuit operators.
  • The native adapter now binds a let value with its own operation, matching the Haskell adapter. The extra temporary made the two adapters disagree for every non-atomic value, which ?: would have exposed.

Limits

  • Conditional results are bool or numeric only (VXT0039, VXC1070). A slot holding an owned value needs move and release rules the backend does not have.
  • Assignment is still a statement with a named target; a = b = 10 and (value += 5) are not implemented.
  • Known and unchanged: the Haskell adapter spells the zero of a floating condition comparison as an integer payload, the native one as a floating literal. An existing test pins the Haskell form; it is not touched here.

Evidence

  • 115 new Haskell cases; native CorePrep-shape, verifier and wire tests; JIT execution tests under both optimizer settings whose unselected arm divides by zero or recurses without bound.
  • The differential generator has three new program shapes with host-computed expectations; the smoke program runs 216 cases.
  • Local (Windows): cabal compiler and fuzz-feedback suites, develop test (21 native suites), verify-docs, verify-examples, clang-format, git diff --check — all pass.
  • Not run locally: ASan/UBSan suites, libFuzzer campaigns, macOS and Linux.

…nd discard

Language
- condition ? first : second evaluates exactly one result.
- left ?: fallback (also spelled left ? : fallback) keeps a left value that
  is true in Boolean context and evaluates the fallback only otherwise; the
  left operand is evaluated once.
- Compound assignment statements += -= *= /= //= %= **= <<= >>= &= ^= |=,
  also accepted in for update lists, and the discard statement _ = value;.
- ?? and ??= are lexed as their own tokens and rejected with VXP0030 and
  VXP0031 until nullable types exist.

Frontend
- Four new AST nodes carried through the renamer, name resolution, closure
  analysis, constant evaluation, the template passes, the type checker and
  the desugarer. Wildcard fallbacks that would have treated a conditional
  as call-free or definition-free were replaced by explicit cases.
- An untyped numeric literal operand takes the type of the other operand in
  either direction. The order is chosen from syntax so each operand is
  checked once; chained conditionals stay linear.
- New diagnostics VXP0029, VXT0035 to VXT0039.

Core
- Lazy CoreConditional in the Haskell and native models, both verifiers
  (VXC1067 to VXC1071) and both wire codecs. Core wire is now v8 with
  expression tag 6; CorePrep, Xpp and Xmm are unchanged.
- Effect inference, integer facts, constant folding, control-flow
  simplification, liveness and inlining treat the two arms as alternative
  paths rather than a sequence.
- Both CorePrep adapters lower the expression to a branch over one result
  slot that is seeded before the branch and assigned in each arm block.
- The native adapter now binds a let value with its own operation, as the
  Haskell adapter does; the extra copied temporary made the two disagree
  for every non-atomic value.

Limits
- Conditional results are bool or numeric only (VXT0039, VXC1070). A slot
  holding an owned value needs move and release rules the backend lacks.
- Assignment remains a statement with a named target.

Tests
- 115 Haskell cases over lexing, parsing, typing, lowering, verification,
  optimization, CorePrep shape and template instantiation.
- Native CorePrep shape, verifier and wire tests, and JIT execution tests
  under both optimizer settings whose unselected arm divides by zero or
  recurses without bound.
- The differential generator gains three program shapes with host-computed
  expectations; the smoke program now runs 216 shape and trip-count cases.
- Six corpus seeds for the lexer, parser, source and differential targets.

Verified locally on Windows: cabal compiler and fuzz-feedback suites,
develop test (21 native suites), verify-docs, verify-examples,
clang-format and git diff --check. Sanitizer and libFuzzer campaigns were
not run locally.
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.

1 participant