frontend/gda_expr API
frontend/gda_expr は General Decimal Arithmetic のテストファイル(Cowlishaw の 10 進仕様の .decTest 形式)を読み込み、その行を decimal_gda に対して実行します。構文解析はすべての行を、そのコンテキストと numeric_expr の式を持つ GdaCase に変換します。実行は式を評価し、結果とステータスフラグを行と比較します。このパッケージはファイルやプロセスの IO を行いません。コマンドラインランナーは cli/gda_expr_cli です。ワークフローはチュートリアルで示し、行の対応付けと合格規則は設計ページで規定します。
moon.pkg でパッケージをインポートします:
import {
"Luna-Flow/floating/frontend/gda_expr",
}
解析
parse_dectest
parse_dectest(source, text) は .decTest 文書全体を構文解析します。
pub fn parse_dectest(String, String) -> Result[GdaDocument, Array[ParseDiagnostic]]
source はスパンで使われる名前(通常はファイルパス)で、text はファイルの内容です。テキストは \n で分割され、行番号は 1 から始まります。各行は次のように扱われます。
- 引用符の外の
--はコメントを開始し、行の残りは捨てられます。先頭と末尾の空白は除去され、空行はスキップされます。 - 引用符の外に
->を含まない行はディレクティブname: valueです。名前は-、_、空白、タブを除去したうえで大文字小文字を区別せずに比較されます。precision、rounding、minexponent、maxexponent、clamp、extended、dectestはコンテキストを更新し、versionと未知の名前は無視されます。precision、minExponent、maxExponentは整数でなければならず、そうでなければその行は診断になります。clampは値1のときだけ有効になり、extendedは値0のときだけ無効になります。:を含まない行は診断になります。 ->を含む行はテスト行です。左辺はid operation operand…(2 トークン以上)に、右辺はexpected condition…(1 トークン以上)にトークン化されます。トークンは空白、タブ、改行で区切られます。'…'または"…"で囲まれたトークンは空白を含むことができ、引用符は取り除かれます。->の後の閉じられていない引用符は診断unterminated quoted tokenになります。->の前で開かれた引用符は矢印を隠すため、その行はexpected directive or testcase rowとして報告されます。トークンが必要数に満たない場合はmalformed testcase rowになります。
診断が生成されなかった場合、結果は Ok(document) です。そうでなければ、文書のすべての診断を行順に含む Err です。
文書と行
GdaDocument
GdaDocument は構文解析済みのファイルで、ソース名とファイル順の行を持ちます。
pub struct GdaDocument {
// private fields
}
GdaDocument::source, GdaDocument::cases, GdaDocument::case_count
これらのメソッドはソース名、行のコピー、行数を返します。
pub fn GdaDocument::source(Self) -> String
pub fn GdaDocument::cases(Self) -> Array[GdaCase]
pub fn GdaDocument::case_count(Self) -> Int
GdaCase
GdaCase は 1 つのテスト行と、その行の時点で有効なコンテキストの組です。
pub struct GdaCase {
// private fields
}
GdaCase::id, GdaCase::operation, GdaCase::normalized_operation
これらのメソッドは行 id、記述どおりの演算、およびディスパッチに使われる演算名(小文字にし、-、_、空白、タブを除去したもの)を返します。
pub fn GdaCase::id(Self) -> String
pub fn GdaCase::operation(Self) -> String
pub fn GdaCase::normalized_operation(Self) -> String
GdaCase::operands, GdaCase::expected, GdaCase::conditions
これらのメソッドはオペランドのトークン、期待結果のトークン、条件のトークンを返します。引用符は外されますが、それ以外は記述どおりです。
pub fn GdaCase::operands(Self) -> Array[String]
pub fn GdaCase::expected(Self) -> String
pub fn GdaCase::conditions(Self) -> Array[String]
配列はコピーです。
GdaCase::context, GdaCase::span, GdaCase::expression
これらのメソッドは行のディレクティブコンテキスト、そのスパン(ソース、行、列 1)、および式としての行を返します。
pub fn GdaCase::context(Self) -> GdaContext
pub fn GdaCase::span(Self) -> @numeric_expr.SourceSpan
pub fn GdaCase::expression(Self) -> @numeric_expr.Expr
式は、オペランドごとに 1 つの Expr::literal に適用された Expr::invoke(Operation::new(normalized_operation), …) で、すべて行のスパンを持ちます。
GdaContext
GdaContext は、ある行における文書のディレクティブ状態です。
pub struct GdaContext {
// private fields
} derive(Eq, @debug.Debug)
これは記述どおりのディレクティブ値のレコードであり、@decimal_gda.GdaContext ではありません。実行時に変換されます。
GdaContext::default
GdaContext::default() は最初のディレクティブより前のコンテキストです。
pub fn GdaContext::default() -> Self
精度 34、丸め "half_even"、min_exponent 、max_exponent 、clamp 無効、extended 有効、dectest は空。
GdaContext::precision, rounding, min_exponent, max_exponent, clamp, extended, dectest
これらのアクセサはディレクティブの値を返します。
pub fn GdaContext::precision(Self) -> Int
pub fn GdaContext::rounding(Self) -> String
pub fn GdaContext::min_exponent(Self) -> Int
pub fn GdaContext::max_exponent(Self) -> Int
pub fn GdaContext::clamp(Self) -> Bool
pub fn GdaContext::extended(Self) -> Bool
pub fn GdaContext::dectest(Self) -> String
rounding は記述どおりのディレクティブのテキスト(例えば "half_up" や "05up")であり、実行時にのみ解釈されます。
ParseDiagnostic
ParseDiagnostic は位置情報付きの 1 つの構文解析エラーです。
pub struct ParseDiagnostic {
// private fields
} derive(Eq, @debug.Debug)
ParseDiagnostic::span, ParseDiagnostic::message
これらのメソッドは位置(ソース、行、列 1)とメッセージを返します。メッセージは例えば "unterminated quoted token"、"malformed testcase row"、"expected directive or testcase row"、"invalid precision directive" です。
pub fn ParseDiagnostic::span(Self) -> @numeric_expr.SourceSpan
pub fn ParseDiagnostic::message(Self) -> String
///|
test "parse diagnostics" {
let text =
#|precision: nine
#|t1 add 1 1 -> 2
#|t2 add 1 1 -> '2
#|t3 add 1 1
#|
match @gda_expr.parse_dectest("bad.decTest", text) {
Err(diagnostics) => {
let lines = diagnostics.map(d => {
d.span().line().to_string() + " " + d.message()
})
inspect(
lines.join("; "),
content="1 invalid precision directive; 3 unterminated quoted token; 4 expected directive or testcase row",
)
}
Ok(_) => fail("expected diagnostics")
}
}
実行
execute_documents
execute_documents(documents, options?) は文書の選択された行を順に実行し、結果を要約します。
pub fn execute_documents(Array[GdaDocument], options? : RunOptions) -> RunSummary
行は文書ごとにファイル順に処理されます。id が options.case_filter() に一致しない行は完全に無視されます。残りの行には と番号が付けられ、シャード数 、シャードインデックス に対して のとき行 が実行されます。実行される各行には、まず処置区分が与えられます。
- オペランドがちょうど
#か?である場合、または期待結果がちょうど#である場合はDiagnostic。 - 条件が 13 個の GDA 条件のいずれでもない場合、演算が実装されていない場合、または丸めディレクティブが認識されない場合は
Unsupported。 - それ以外は
Executable。
評価されるのは Executable の行だけです。結果が期待トークンに一致し、発生した条件が列挙されたものとちょうど一致するとき、その行は合格です。完全な規則は設計ページにあります。実行対象でない行は passed() == false とメッセージ "skipped" を受け取り、失敗ではなくスキップとして数えられます。この関数は行の内容によって異常終了することはありません。
RunOptions
RunOptions は execute_documents が実行する行を選択します。
pub struct RunOptions {
// private fields
} derive(Eq, @debug.Debug)
RunOptions::new
RunOptions::new(shard_count?, shard_index?, strict_supported?, case_filter?) はオプションを構築します。
pub fn RunOptions::new(shard_count? : Int, shard_index? : Int, strict_supported? : Bool, case_filter? : String) -> Self
デフォルト:シャード 1 つ、インデックス 0、strict_supported 無効、空のフィルタ(全行)。shard_count > 0 かつ 0 <= shard_index < shard_count でなければ異常終了します。
case_filter はカンマ区切りのセレクタのリストで、各セレクタは前後の空白が除去されます。セレクタ id はその id にちょうど一致します。セレクタ first..last は、first および last と同じ長さを持ち、文字列順でその間にあるすべての id に一致します。そのため、add001..add099 は番号付きのブロックを選択します。
strict_supported は呼び出し側のために保持されるもので、execute_documents 自体はこれを読みません。CLI はこれを使って、サポートされない行を失敗の終了コードに変えます。
RunOptions::shard_count, shard_index, strict_supported, case_filter
これらのアクセサはオプションの値を返します。
pub fn RunOptions::shard_count(Self) -> Int
pub fn RunOptions::shard_index(Self) -> Int
pub fn RunOptions::strict_supported(Self) -> Bool
pub fn RunOptions::case_filter(Self) -> String
結果
CaseDisposition
CaseDisposition は行が実行されたかどうか、また実行されなかった場合はその理由を示します。
pub(all) enum CaseDisposition {
Executable
Diagnostic(String)
Legacy(String)
Unsupported(String)
}
文字列は "diagnostic interchange/non-scalar row" や "unsupported operation frobnicate" のような短い理由です。Legacy は共通の結果モデルのために存在しますが、現在のエグゼキュータがこれを割り当てることはありません。
CaseResult
CaseResult は選択された 1 つの行の結果です。
pub struct CaseResult {
// private fields
}
CaseResult::id, disposition, passed, message
これらのメソッドは行 id、その処置区分、合格したかどうか、およびメッセージを返します。メッセージは、合格なら空、実行対象でない行なら "skipped"、オペランドをデコードできなかったか演算がオペランドを拒否した場合は "evaluation failed"、それ以外は "result mismatch: expected …, actual …" または "status flags mismatch: expected …, actual …" というテキストです。
pub fn CaseResult::id(Self) -> String
pub fn CaseResult::disposition(Self) -> CaseDisposition
pub fn CaseResult::passed(Self) -> Bool
pub fn CaseResult::message(Self) -> String
RunSummary
RunSummary は 1 回の実行の結果を集計します。
pub struct RunSummary {
// private fields
}
RunSummary のカウンタ
これらのメソッドは 1 回の実行の件数を返します。
pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::selected_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::skipped_cases(Self) -> Int
pub fn RunSummary::diagnostic_cases(Self) -> Int
pub fn RunSummary::legacy_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int
total_cases はフィルタに一致する行(全シャード)を数え、selected_cases はこのシャードで実行された行を数えます。これらは次を満たします。
RunSummary::results, RunSummary::success
results は行ごとの結果のコピーを実行順に返します。success は実行対象の行が 1 つも失敗しなかったとき真です。
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::success(Self) -> Bool
スキップされた行は success に影響しません。
RunSummary::merge
RunSummary::merge(parts) は 1 回の実行の各シャードの要約を結合します。
pub fn RunSummary::merge(Array[Self]) -> Self
total_cases 以外のすべてのカウンタは加算されます。total_cases は各部分の最大値です(どのシャードも同じ合計を報告します)。結果は parts の順に連結されます。1 回の実行の 個のシャードをマージすると、シャード分割しない実行と同じカウンタが得られます。
///|
test "merge shards" {
let text =
#|s1 add 1 1 -> 2
#|s2 add 1 2 -> 3
#|s3 add 1 3 -> 5
#|
let document = @gda_expr.parse_dectest("s.decTest", text).unwrap()
let parts = [0, 1].map(i => {
@gda_expr.execute_documents(
[document],
options=@gda_expr.RunOptions::new(shard_count=2, shard_index=i),
)
})
let merged = @gda_expr.RunSummary::merge(parts)
inspect(merged.total_cases(), content="3")
inspect(merged.passed_cases(), content="2")
inspect(merged.failed_cases(), content="1")
}
トレイト実装
GdaContext、ParseDiagnostic、RunOptions の等価性と Debug
これらのメソッドはすべてのフィールドを比較し、値を Debug 用に描画します。新しいコードでは ==、!=、debug_inspect を使ってください。
pub fn GdaContext::equal(Self, Self) -> Bool
pub fn GdaContext::not_equal(Self, Self) -> Bool
pub fn GdaContext::to_repr(Self) -> @debug.Repr
pub fn ParseDiagnostic::equal(Self, Self) -> Bool
pub fn ParseDiagnostic::not_equal(Self, Self) -> Bool
pub fn ParseDiagnostic::to_repr(Self) -> @debug.Repr
pub fn RunOptions::equal(Self, Self) -> Bool
pub fn RunOptions::not_equal(Self, Self) -> Bool
pub fn RunOptions::to_repr(Self) -> @debug.Repr
公開インターフェース全体
このスナップショットは、パッケージの生成された pkg.generated.mbti です。説明文とインターフェースが食い違う場合は、こちらが正となります。
// Generated using `moon info`, DON'T EDIT IT
package "Luna-Flow/floating/frontend/gda_expr"
import {
"Luna-Flow/floating/numeric_expr",
"moonbitlang/core/debug",
}
// Values
pub fn execute_documents(Array[GdaDocument], options? : RunOptions) -> RunSummary
pub fn parse_dectest(String, String) -> Result[GdaDocument, Array[ParseDiagnostic]]
// Errors
// Types and methods
pub(all) enum CaseDisposition {
Executable
Diagnostic(String)
Legacy(String)
Unsupported(String)
}
pub struct CaseResult {
// private fields
}
pub fn CaseResult::disposition(Self) -> CaseDisposition
pub fn CaseResult::id(Self) -> String
pub fn CaseResult::message(Self) -> String
pub fn CaseResult::passed(Self) -> Bool
pub struct GdaCase {
// private fields
}
pub fn GdaCase::conditions(Self) -> Array[String]
pub fn GdaCase::context(Self) -> GdaContext
pub fn GdaCase::expected(Self) -> String
pub fn GdaCase::expression(Self) -> @numeric_expr.Expr
pub fn GdaCase::id(Self) -> String
pub fn GdaCase::normalized_operation(Self) -> String
pub fn GdaCase::operands(Self) -> Array[String]
pub fn GdaCase::operation(Self) -> String
pub fn GdaCase::span(Self) -> @numeric_expr.SourceSpan
pub struct GdaContext {
// private fields
} derive(Eq, @debug.Debug)
pub fn GdaContext::clamp(Self) -> Bool
pub fn GdaContext::dectest(Self) -> String
pub fn GdaContext::default() -> Self
pub fn GdaContext::equal(Self, Self) -> Bool
pub fn GdaContext::extended(Self) -> Bool
pub fn GdaContext::max_exponent(Self) -> Int
pub fn GdaContext::min_exponent(Self) -> Int
pub fn GdaContext::not_equal(Self, Self) -> Bool
pub fn GdaContext::precision(Self) -> Int
pub fn GdaContext::rounding(Self) -> String
pub fn GdaContext::to_repr(Self) -> @debug.Repr
pub struct GdaDocument {
// private fields
}
pub fn GdaDocument::case_count(Self) -> Int
pub fn GdaDocument::cases(Self) -> Array[GdaCase]
pub fn GdaDocument::source(Self) -> String
pub struct ParseDiagnostic {
// private fields
} derive(Eq, @debug.Debug)
pub fn ParseDiagnostic::equal(Self, Self) -> Bool
pub fn ParseDiagnostic::message(Self) -> String
pub fn ParseDiagnostic::not_equal(Self, Self) -> Bool
pub fn ParseDiagnostic::span(Self) -> @numeric_expr.SourceSpan
pub fn ParseDiagnostic::to_repr(Self) -> @debug.Repr
pub struct RunOptions {
// private fields
} derive(Eq, @debug.Debug)
pub fn RunOptions::case_filter(Self) -> String
pub fn RunOptions::equal(Self, Self) -> Bool
pub fn RunOptions::new(shard_count? : Int, shard_index? : Int, strict_supported? : Bool, case_filter? : String) -> Self
pub fn RunOptions::not_equal(Self, Self) -> Bool
pub fn RunOptions::shard_count(Self) -> Int
pub fn RunOptions::shard_index(Self) -> Int
pub fn RunOptions::strict_supported(Self) -> Bool
pub fn RunOptions::to_repr(Self) -> @debug.Repr
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::legacy_cases(Self) -> Int
pub fn RunSummary::merge(Array[Self]) -> Self
pub fn RunSummary::passed_cases(Self) -> Int
pub fn RunSummary::results(Self) -> Array[CaseResult]
pub fn RunSummary::selected_cases(Self) -> Int
pub fn RunSummary::skipped_cases(Self) -> Int
pub fn RunSummary::success(Self) -> Bool
pub fn RunSummary::total_cases(Self) -> Int
pub fn RunSummary::unsupported_cases(Self) -> Int
// Type aliases
// Traits