Skip to content

Implement units.parse and units.parse_bytes builtins#152

Open
glasses-and-hat wants to merge 1 commit into
open-policy-agent:mainfrom
glasses-and-hat:implement-units-parsing-builtins
Open

Implement units.parse and units.parse_bytes builtins#152
glasses-and-hat wants to merge 1 commit into
open-policy-agent:mainfrom
glasses-and-hat:implement-units-parsing-builtins

Conversation

@glasses-and-hat

@glasses-and-hat glasses-and-hat commented Jul 12, 2026

Copy link
Copy Markdown

Summary

Implements the units.parse and units.parse_bytes OPA builtins (closes #133), which were previously unimplemented and raised FunctionNotFoundError for every call.

  • Both parse strings like "10K", "1.5Gi", "100m" into a number, supporting the standard SI decimal (k/K, M, G, T, P, E) and binary (Ki, Mi, Gi, Ti, Pi, Ei) suffixes, plus the m (milli) suffix for units.parse.
  • Follows the same string-scanning algorithm as the reference Go implementation (extractNumAndUnit in topdown/parse_bytes.go / topdown/parse_units.go), including scientific-notation handling and the exponent too large guard (max 6 exponent digits).
  • Uses BigDecimal for exact arithmetic rather than double, to avoid floating-point precision loss on suffix multiplication (mirrors the reference implementation's use of big.Rat/big.Float):
    • units.parse_bytes truncates the product towards zero (matches big.Float.Int()).
    • units.parse returns an exact integer when the product has no fractional part, otherwise rounds to 10 decimal places (matches big.Rat.FloatString(10)).
  • Error messages (no amount provided, could not parse amount to a number, spaces not allowed in resource strings, exponent too large, unit X not recognized) match the reference implementation's wording.
  • Registered as core builtins in BuiltinRegistry.BUILTIN_CLASSES (no external dependencies needed, consistent with ArithmeticBuiltins/HexBuiltins).

Test plan

  • All 66 pre-existing compliance test cases under opa-evaluator/src/test/resources/compliance/.../TestData/v1/units/ (covering both happy-path and error cases, including the precision-regression cases in test-units-precision.json and test-issue-4856.json) now pass — previously they were silently skipped via the compliance suite's "missing builtin" allowance.
  • Confirmed units.parse/units.parse_bytes no longer appear in the compliance suite's "Missing Builtin Report".
  • Full opa-evaluator test suite passes (./gradlew :opa-evaluator:test), no regressions.
  • ./gradlew checkstyleMain checkstyleTest pmdMain pmdTest clean for the new file.
  • ./gradlew compileJava succeeds across all modules.

Adds the units.parse and units.parse_bytes OPA builtins, which were
previously unimplemented and raised FunctionNotFoundError. Both accept
strings like "10K", "1.5Gi", or "100m" and convert them to a number,
supporting the standard SI decimal (k/K, M, G, T, P, E) and binary
(Ki, Mi, Gi, Ti, Pi, Ei) suffixes, plus the milli ("m") suffix for
units.parse.

Arithmetic is done with BigDecimal to avoid floating-point precision
loss, mirroring the reference Go implementation's use of big.Rat/
big.Float: units.parse_bytes truncates towards zero, while
units.parse produces an exact integer when possible and otherwise
rounds to 10 decimal places.

Fixes open-policy-agent#133
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.

Implement units parsing builtins (units.*)

1 participant