frontend/itl_expr API

frontend/itl_expr は ITF1788 スイート(IEEE 1788-2015 区間規格のテストデータ)の ITL 形式の区間テストケースを構文解析し、ball_float に対して実行します。これは純粋なライブラリで、コマンドラインランナーは cli/itl_expr_cli です。ワークフローはチュートリアルで順を追って説明し、合格規則は設計ページで示します。

moon.pkg でパッケージをインポートします:

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

解析

parse_itl

parse_itl(source) は ITL テキストをケースに構文解析します。

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

テキストは 1 行ずつ読まれ、各行は前後の空白が除去されます。

  • // で始まる行と空行はスキップされます。/* で始まる行はブロックコメントを開始し、そのコメントは以降で最初に */ を含む行(または同じ行)で終わります。
  • testcase NAME … は新しいブロックを開始します。NAME は testcase の後の語で、後ろに空白が続かなければならず、そうでなければ診断 "invalid testcase declaration" が記録されます。文のカウンタは 0 から再開します。
  • } に等しい行はスキップされます。
  • それ以外のすべての行は(空白を挟んで)現在の文に追加され、; で終わる行が文を完結させます。

完結した文 left = expected は最初の = で分割されます。左辺は角括弧の外の空白とタブで語に分割され、最初の語が演算、残りがオペランドです。ケース id は NAME:k で、k はブロック内の文を 1 から数えたものです(最初の testcase より前の文は名前 anonymous を使います)。= を含まない文や演算のない文は診断 "NAME:k: missing '='" または "NAME:k: missing operation" になり、最後の ; の後に残ったテキストは "unterminated ITL statement" になります。診断がなければ結果は Ok(cases)、そうでなければ Err(diagnostics) です。

ItlCase

ItlCase は構文解析済みの 1 つの文です。

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

ItlCase::id, operation, operands, expected

これらのメソッドは id NAME:k、演算の語、オペランドの語のコピー、および期待テキスト(前後の空白を除去し、装飾の接尾辞があればそれも含む)を返します。

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

実行

execute_case

execute_case(case, precision?) は 1 つのケースを実行し、その結果を返します。

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

precision(デフォルト 53)は端点を読み取る際に使うビット精度です。区間の結果は precision に関係なく @ball_float.BallContext::binary64() で丸められるため、ITF1788 のデータに対して意味のある値はデフォルト値です。

オペランドと期待値は次のように読み取られます。区間リテラルは [lo,hi]、[empty]、[entire]、[nai] のいずれかで、その後に _dec を続けることができます。dec は com、dac、def、trv、ill のいずれかです(デフォルトは com)。端点は、省略可能な符号付きの inf/infinity、16 進浮動小数点数 0x…p…、または 10 進テキストです。10 進および 16 進の端点は precision ビットで最近接偶数丸めされます。

ケースは演算と期待値に基づいてディスパッチされます。

ケース演算期待値比較
真偽値isEmpty, isEntire, isNaI, isCommonInterval, isSingleton, equal, subset, interior, disjoint, precedes, strictPrecedes, less, strictLess, isMembertrue または false真偽値が等しい
重なりoverlap重なり状態の名前(before、meets、overlaps、starts、containedBy、finishes、equals、after、metBy、overlappedBy、startedBy、contains、finishedBy、bothEmpty、firstEmpty、secondEmpty、undefined)名前が等しい
数値inf, sup, mid, rad, wid, mag, mig端点数が等しい
単項pos, neg, abs, recip, sqr, sqrt, exp, exp2, exp10, log, log2, log10, sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh区間集合として等しい
三項fma区間集合として等しい
整数べきpown(第 2 オペランドは整数)区間集合として等しい
二項add, sub, mul, div, pow, atan2, min, max, intersection, convexHull, cancelPlus, cancelMinus区間集合として等しい

「集合として等しい」とは、両方が NaI であるか、両方が空であるか、下端どうし・上端どうしが等しい(数値として比較するので −0=+0-0 = +0)ことを意味します。期待テキストが _ を含む場合は、装飾も等しくなければなりません。期待テキストが true または false のときは常に真偽値のディスパッチが選ばれます。

処置区分:

  • ケースが実行された場合は Executable。結果は passed() で分かります。
  • 未知の演算、期待値が区間でない二項ディスパッチのケース(例えば signal 注釈が後に続くもの)、オペランドが 2 つでない二項ディスパッチのケース、または第 2 オペランドが欠けているか読み取れない二項の真偽値述語の場合は Unsupported(reason)。
  • 真偽値ケースの第 1 オペランド、または重なり・数値・単項・三項・整数べきのディスパッチのオペランドか期待値が読み取れない場合、あるいは二項ディスパッチのオペランドが区間リテラルでない場合は Diagnostic(reason)。

execute_case はケースの内容によって異常終了しません。

summarize_results

summarize_results(results) は結果のリストを集計します。

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

total_cases はリストの長さです。

結果

ItlDisposition

ItlDisposition はケースが実行されたかどうかを示します。

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

ItlResult

ItlResult は 1 つのケースの結果です。

pub struct ItlResult {
  // private fields
}

ItlResult::id, disposition, passed, message

これらのメソッドはケース id、処置区分、合格したかどうか、およびメッセージを返します。メッセージは、成功なら空、不一致なら "expected E, got A"(区間は BallFloatDecorated::to_string で出力)、それ以外は短い理由または問題のテキストです。

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 は結果のリストを集計します。

pub struct RunSummary {
  // private fields
}

RunSummary のカウンタと結果

これらのメソッドは件数、結果のコピー、全体の判定を返します。

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} および executable=passed+failed\text{executable} = \text{passed} + \text{failed} が成り立ちます。success() は、実行対象のケースが 1 つも失敗せず、かつ診断ケースが 1 つもないとき真です。サポートされないケースは影響しません。

///|
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")
}

トレイト実装

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

これらのメソッドは 2 つのケースのすべてのフィールドを比較し、ケースを Debug 用に描画します。新しいコードでは ==、!=、debug_inspect を使ってください。

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

公開インターフェース全体

このスナップショットは、パッケージの生成された pkg.generated.mbti です。説明文とインターフェースが食い違う場合は、こちらが正となります。

// 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