frontend/itl_expr API

frontend/itl_expr parses interval test cases in the ITL format of the ITF1788 suite (test data for the IEEE 1788-2015 interval standard) and executes them against ball_float. It is a pure library: the command-line runner is cli/itl_expr_cli. The tutorial walks through the workflow and the design page gives the pass rule.

Import the package in moon.pkg:

import {
  "Luna-Flow/floating/frontend/itl_expr",
}

Parsing

parse_itl

parse_itl(source) parses ITL text into cases.

pub fn parse_itl(String) -> Result[Array[ItlCase], Array[String]]

The text is read line by line, each line trimmed:

  • lines starting with // and empty lines are skipped; a line starting with /* starts a block comment that ends on the first later line containing */ (or on the same line);
  • testcase NAME … starts a new block; NAME is the word after testcase and must be followed by a space, otherwise the diagnostic "invalid testcase declaration" is recorded; the statement counter restarts at 0;
  • a line equal to } is skipped;
  • every other line is appended (with a space) to the current statement, and a line ending in ; completes it.

A completed statement left = expected is split at the first =. The left side is split into words at spaces and tabs outside square brackets; the first word is the operation and the rest are operands. The case id is NAME:k, where k counts statements in the block from 1 (statements before the first testcase use the name anonymous). A statement without = or without an operation is a diagnostic "NAME:k: missing '='" or "NAME:k: missing operation"; text left after the last ; gives "unterminated ITL statement". The result is Ok(cases) when there is no diagnostic and Err(diagnostics) otherwise.

ItlCase

ItlCase is one parsed statement.

pub struct ItlCase {
  // private fields
} derive(Eq, @debug.Debug)

ItlCase::id, operation, operands, expected

These methods return the id NAME:k, the operation word, a copy of the operand words and the expected text (trimmed, including any decoration suffix).

pub fn ItlCase::id(Self) -> String
pub fn ItlCase::operation(Self) -> String
pub fn ItlCase::operands(Self) -> Array[String]
pub fn ItlCase::expected(Self) -> String

Execution

execute_case

execute_case(case, precision?) executes one case and returns its result.

pub fn execute_case(ItlCase, precision? : Int) -> ItlResult

precision (default 53) is the bit precision used to read bounds. Interval results are rounded with @ball_float.BallContext::binary64() regardless of precision, so the default is the meaningful value for ITF1788 data.

Operands and expected values are read as follows. An interval literal is [lo,hi], [empty], [entire] or [nai], optionally followed by _dec with dec one of com, dac, def, trv, ill (default com). A bound is inf/infinity with an optional sign, a hexadecimal float 0x…p…, or decimal text. Decimal and hexadecimal bounds are rounded to nearest-even at precision bits.

The case is dispatched on its operation and expected value:

CaseOperationsExpectedComparison
booleanisEmpty, isEntire, isNaI, isCommonInterval, isSingleton, equal, subset, interior, disjoint, precedes, strictPrecedes, less, strictLess, isMembertrue or falseequal booleans
overlapoverlapan overlap state name (before, meets, overlaps, starts, containedBy, finishes, equals, after, metBy, overlappedBy, startedBy, contains, finishedBy, bothEmpty, firstEmpty, secondEmpty, undefined)equal names
numericinf, sup, mid, rad, wid, mag, miga boundequal numbers
unarypos, neg, abs, recip, sqr, sqrt, exp, exp2, exp10, log, log2, log10, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanhintervalequal sets
ternaryfmaintervalequal sets
integer powerpown (second operand an integer)intervalequal sets
binaryadd, sub, mul, div, pow, atan2, min, max, intersection, convexHull, cancelPlus, cancelMinusintervalequal sets

“Equal sets” means: both NaI, or both empty, or equal lower bounds and equal upper bounds (compared numerically, so −0=+0-0 = +0). When the expected text contains _, the decorations must also be equal. The boolean dispatch is chosen whenever the expected text is true or false.

Dispositions:

  • Executable when the case was run; passed() tells the outcome;
  • Unsupported(reason) for an unknown operation, a binary-dispatch case whose expected value is not an interval (for example one followed by a signal annotation), a binary-dispatch case with other than two operands, or a binary boolean predicate whose second operand is missing or unreadable;
  • Diagnostic(reason) when the first operand of a boolean case, or an operand or the expected value of the overlap, numeric, unary, ternary or integer-power dispatch, cannot be read, or an operand of the binary dispatch is not an interval literal.

execute_case does not abort on case content.

summarize_results

summarize_results(results) counts a list of results.

pub fn summarize_results(Array[ItlResult]) -> RunSummary

total_cases is the length of the list.

Results

ItlDisposition

ItlDisposition says whether a case was executed.

pub(all) enum ItlDisposition {
  Executable
  Unsupported(String)
  Diagnostic(String)
}

ItlResult

ItlResult is the outcome of one case.

pub struct ItlResult {
  // private fields
}

ItlResult::id, disposition, passed, message

These methods return the case id, the disposition, whether the case passed, and a message: empty on success, "expected E, got A" on a mismatch (intervals printed by BallFloatDecorated::to_string), and a short reason or the offending text otherwise.

pub fn ItlResult::id(Self) -> String
pub fn ItlResult::disposition(Self) -> ItlDisposition
pub fn ItlResult::passed(Self) -> Bool
pub fn ItlResult::message(Self) -> String

RunSummary

RunSummary aggregates a list of results.

pub struct RunSummary {
  // private fields
}

RunSummary counters and results

These methods return the counts, a copy of the results, and the overall verdict.

pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::executable_cases(Self) -> Int
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int
pub fn RunSummary::diagnostic_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[ItlResult]
pub fn RunSummary::success(Self) -> Bool

total=executable+unsupported+diagnostic\text{total} = \text{executable} + \text{unsupported} + \text{diagnostic} and executable=passed+failed\text{executable} = \text{passed} + \text{failed}. success() is true when no executable case failed and there is no diagnostic case; unsupported cases do not affect it.

///|
test "itl summary" {
  let source =
    #|testcase s {
    #|  sub [1.0,2.0] [3.0,4.0] = [-3.0,-1.0];
    #|  sqr [-2.0,1.0] = [0.0,4.0];
    #|  mid [1.0,2.0] = 1.5;
    #|  isEmpty [empty] = true;
    #|}
  let summary = @itl_expr.summarize_results(
    @itl_expr.parse_itl(source).unwrap().map(c => @itl_expr.execute_case(c)),
  )
  inspect(summary.total_cases(), content="4")
  inspect(summary.passed_cases(), content="4")
}

Trait implementations

ItlCase::equal, ItlCase::not_equal, ItlCase::to_repr

These methods compare all fields of two cases and render a case for Debug. Use ==, != and debug_inspect in new code.

pub fn ItlCase::equal(Self, Self) -> Bool
pub fn ItlCase::not_equal(Self, Self) -> Bool
pub fn ItlCase::to_repr(Self) -> @debug.Repr

Complete public interface

This snapshot is the generated pkg.generated.mbti of the package. It is the authority when prose and interface disagree.

// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/frontend/itl_expr"

import {
  "moonbitlang/core/debug",
}

// Values
pub fn execute_case(ItlCase, precision? : Int) -> ItlResult

pub fn parse_itl(String) -> Result[Array[ItlCase], Array[String]]

pub fn summarize_results(Array[ItlResult]) -> RunSummary

// Errors

// Types and methods
pub struct ItlCase {
  // private fields
} derive(Eq, @debug.Debug)
pub fn ItlCase::equal(Self, Self) -> Bool
pub fn ItlCase::expected(Self) -> String
pub fn ItlCase::id(Self) -> String
pub fn ItlCase::not_equal(Self, Self) -> Bool
pub fn ItlCase::operands(Self) -> Array[String]
pub fn ItlCase::operation(Self) -> String
pub fn ItlCase::to_repr(Self) -> @debug.Repr

pub(all) enum ItlDisposition {
  Executable
  Unsupported(String)
  Diagnostic(String)
}

pub struct ItlResult {
  // private fields
}
pub fn ItlResult::disposition(Self) -> ItlDisposition
pub fn ItlResult::id(Self) -> String
pub fn ItlResult::message(Self) -> String
pub fn ItlResult::passed(Self) -> Bool

pub struct RunSummary {
  // private fields
}
pub fn RunSummary::diagnostic_cases(Self) -> Int
pub fn RunSummary::executable_cases(Self) -> Int
pub fn RunSummary::failed_cases(Self) -> Int
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[ItlResult]
pub fn RunSummary::success(Self) -> Bool
pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int

// Type aliases

// Traits