# 式

> 変数と警報の条件の後ろにある 1 つの式の言語、何を参照できるか、あらゆる種類のポイントの読み取りの面、評価が守らせる規則、検証が出すメッセージ、そしてスクリプトの編集画面と「参照…」の選択の使い方。

1 つの式の言語が、Logic のページの 2 か所で働きます。[式の変数](logic-variables)が計算するものと、[警報](logic-alarms)が見張る条件です。どちらも、機械に触れられないサンドボックスの中で厳格モードで評価される 1 つの JavaScript の式で、どちらも同じスクリプトの編集画面で編集します。アクションのスクリプトは同じ語彙を使いますが、文の集まりです。その違いは[アクション](logic-actions)にあります。

## 式とは何か {#what-an-expression-is}

式は、ちょうど 1 つの JavaScript の式です。リテラル、四則演算、比較、論理の演算子、条件の `a ? b : c`、文字列の操作、テンプレート文字列、そして JavaScript の組み込みの `Math`、`Date`、`JSON` の呼び出しです。文（`let`、`if`、繰り返し）はアクションのものです。2 つ目の文は「変数が持てるのは 1 つの式だけです。文はアクションに書きます。」として拒否されます。式のどこであっても、代入と `++`／`--` は「式は読み取り専用です。書き込みはアクションに書きます。」として拒否されます。

式は、最上位を根とする[アドレス](logic-address-space)でポイントを参照します。最上位ごとに、式へ渡されるものは次のとおりです。

| 最上位 | 式に渡ってくるもの |
| --- | --- |
| `Connector` のタグ、`Variables`、`Alarms`、Process のユニットの `Channels` | 下に挙げる型付きの読み取りの面を持つ、実時間のオブジェクトです。裸の参照（`Connector.Simulated.Pump.Flow` だけ）はそのポイントの値になり、裸の警報はその `IsActive` になります。 |
| `System`、`Server`、`Assets`、そして Process のユニットの実行の状態、生産性、コマンド、用意 | 値そのものです。数値、文字列、ブール値、時刻のどれかです。そのまま使ってください。付け足すメンバーはありません。現在値のポイントのメンバーを付けると拒否されます。`System.StartTime.Value` は「「System.StartTime」は値です。.Value を付けずに読んでください。」になります。 |

裸で書いた現在値のポイントは値ではなくポイントそのもので、式の全体であるときだけその値を表します。演算子がそれを値として扱う場所では、どの値かを示すメンバーを通して読んでください。真偽を調べる場所では `.ValueToBool()`（`Variables.Start.ValueToBool() ? 1 : 0`）、等しいかを比べる場所では `.Value`、大小を比べたり計算したりする場所では `.ValueToReal()`（`Variables.Level.ValueToReal() > 80`）、警報では `.IsActive` です。検証は、`?:` の条件、`!`、`&&`、`||` の項、比較（`==`、`!=`、`===`、`!==`、`<`、`>`、`<=`、`>=`）、算術（`+`、`-`、`*`、`/`、`%`、前に付けた符号）に書いた裸のポイントを拒否します。そこでは常に真とみなされるか、値が決して読まれないからです。`Variables.Level > 80` は 「「Variables.Level」は値ではなくポイントそのものです。比較や計算ではその値は読まれません。Variables.Level.ValueToReal() で値を読んでください。」になります。関数に渡したポイントと、ポイントのメンバーは、書いたとおりのままです。同じ拒否は、ポイントが決して外れない `??` の左側（`.Value` で読みます）と、ポイントの値を決して文字列に書き込まないテンプレートリテラルの置き場所 `${…}`（`.ValueToString()` で読みます）にも当てはまります。

`System.Now` は評価のその瞬間です。1 回の評価の中では、これをいくつ参照しても同じ時刻を読みます。ほかのすべての時刻と同じく JavaScript の `Date` として渡るので、時刻どうしは自然に比べられ、引き算もできます。`(System.Now - Connector.Simulated.Pump.Run.SourceTimeStamp()) / 1000` は秒になります。

式の変数は、タグ、内部値の変数、警報、Process のポイント、Assets のポイント、System と Server の診断の値を参照できますが、**ほかの式の変数だけは参照できません**。編集画面がそれを拒否します（「「Variables.X」は式の変数です。式からほかの式の変数を参照することはできません。内部値の変数か、もとになるポイントを参照してください。」）。結果が評価の順番に左右されないためです。警報の条件は `Alarms.*` 以外のすべてを参照でき（「警報の条件から、ほかの警報を参照することはできません。」）、ブール値を返さなければなりません。

## ポイントの読み取りの面 {#the-read-surface-of-a-point}

実時間のタグは、次のものを差し出します。

| メンバー | 返すもの | 意味 |
| --- | --- | --- |
| `.Value` | 型を持つ値 | そのタグの[値の変換経路](connector-value-pipeline)を全部通ったあとの工業値 |
| `.ValueRaw` | 型を持つ値 | スケーリングの前の、タグの宣言した型に正規化した生値 |
| `.ValueObject` | 何でも | ドライバーが作ったそのままの値 |
| `.ValueScaled`、`.ValueCalibrated`、`.ValueLimited`、`.ValueRounded` | 数値 | スケール、校正、上下限、小数桁の各段階を通ったあとの値 |
| `.ValueToBool()`、`.ValueToInteger()`、`.ValueToReal()`、`.ValueToString()`、`.ValueToDateTime()` | 変換した値 | 工業値をその分類に変換したもの。値なしは値なしのままです |
| `.State()` | ブール値 | 品質です。読み取りが良好な間は true です |
| `.SourceTimeStamp()` | Date | 機器がその読み取りを作った時刻（プロトコルが時刻を付ける場合、つまり OPC UA）。それ以外は Connector がそれを受け取った時刻で、`.ApplicationTimeStamp()` と同じです |
| `.ApplicationTimeStamp()` | Date | Connector がそれを受け取った時刻 |
| `.Name`、`.EngineeringUnit` | 文字列 | そのタグの名前と単位 |

変数は、`.Value`、5 つの `.ValueTo*()` の変換、`.State()`、`.ApplicationTimeStamp()`、`.Name`、`.EngineeringUnit` を差し出します。警報は、`.IsActive`、`.IsAcked`、`.CurrentState`、`.State()`（直前の周期でその条件を評価できたかどうか）、`.ActiveSince()`、`.LastTransitionAt()`、`.Name` を差し出します。Process のチャネルは、タグに結び付いているときはタグの面を、変数に結び付いているときは変数の面を差し出します。結び付いていないチャネルは何も差し出しません。実時間のオブジェクトのそれ以外には手が届きません。この面の外のメンバーは undefined として読まれ、それを呼び出すと検証で失敗します。「参照…」の選択は、ポイントごとにこれと同じメンバーを並べます。どれも記憶を頼りに入力する必要はありません。

## 評価が守らせる規則 {#the-rules-the-evaluator-enforces}

入力している最中の編集画面でも、100 ms ごとの周期でも、次の規則が働きます。

- **品質の関門。**評価の前に、参照しているポイントはすべて解決して読み直されます。欠けている、悪い、値を持たない、というポイントが 1 つでもあれば、式を走らせずに結果が品質の悪い欠測になります。ですから、オフラインのタグがサンプルを作り出すことはありませんし、`null` がエンジンに届いて `0` になることもありません。読み取りが途絶えたタグ、つまり読み出し周期に 10 秒を足した時間のうちに新しい読み取りが届かないタグは、ここでは失敗した読み取りとして扱われます。[機器が応答しなかったとき](connector-value-pipeline#the-device-did-not-answer)の方針が代替値を示さないかぎり、品質は悪いものになります。
- **有限でない結果は欠測です。**NaN や無限大（0 での除算、定義されない演算）がサンプルになることはありません。
- **暴走の防止。**評価は 250 ms、5,000 文、4 MB のスクリプトのメモリを超えると中止され、品質の悪い欠測として数えられます。エンジンは式の文字ごとに 1 つ保たれるので、ほかの式から何かが漏れることはありません。
- **型合わせ。**成功した結果は、その変数の[出力の型](logic-variables#output-types)に合わせられます。警報の条件はブール値に合わせられ、変換できない結果はその警報の状態をそのままにします。
- **エラーは例外ではなく欠測です。**周期のときの実行時のエラーは欠測になり、診断ログに 1 件残ります（最初の失敗、繰り返している間は要約、回復したときに 1 行）。周期は次の変数へ進みます。

## 検証が拒否するもの {#what-validation-refuses}

編集画面は 0.5 秒ごとに下書きを検証し、値か条件の下に最初の問題を出します。

| メッセージ | 原因 |
| --- | --- |
| 式は必須です。／条件は必須です。 | 編集画面が空です。 |
| 式のエラー：… | 文字が解析できません。 |
| 変数が持てるのは 1 つの式だけです。文はアクションに書きます。 | 文が 2 つ以上ある、または式ではない文がある。 |
| 式は読み取り専用です。書き込みはアクションに書きます。 | 代入、または `++`／`--`。 |
| アドレスは静的でなければなりません。「Root」は、計算した区切りで参照されています。 | `Variables[name]` など、リテラルでない区切り。 |
| アドレス「Connector.Simulated」が不完全です。 | その最上位でポイントを名指しするには、連なりが短すぎる。 |
| 「X」は見つかりませんでした。 | そのアドレスが何にも解決しない。 |
| 「X」は式の変数です。… | ほかの式の変数を参照している。 |
| 「X」は値です。.Value を付けずに読んでください。 | 値として入るポイントに、現在値のポイントのメンバー（`.Value`、`.State()` など）を付けた（`System.StartTime.Value`）。 |
| 「X」は値ではなくポイントそのものです。条件として使うと常に真とみなされます。X.ValueToBool() で値を読んでください。 | 真偽を調べる場所に裸で書いた現在値のポイント：`?:` の条件、または `!`、`&&`、`\|\|` の項（`!Variables.Start`）。警報ではメッセージは `.IsActive` を示す。 |
| 「X」は値ではなくポイントそのものです。比較や計算ではその値は読まれません。X.ValueToReal() で値を読んでください。 | 比較や算術に裸で書いた現在値のポイント（`Variables.Level > 80`、`Variables.Level * 2`）。`==`、`!=`、`===`、`!==` ではメッセージは `.Value` を、警報では `.IsActive` を示す。 |
| 「X」は値ではなくポイントそのものです。決して空にならないので、?? は常にそれを残します。X.Value で値を読んでください。 | `??` の左に裸で書いた現在値のポイント（`Variables.Level ?? 0`）。警報ではメッセージは `.IsActive` を示す。 |
| 「X」は値ではなくポイントそのものです。文字列に埋め込んでも値は表示されません。X.ValueToString() で値を読んでください。 | テンプレートリテラルの置き場所 `${…}` に裸で書いた現在値のポイント。警報ではメッセージは `.IsActive` を示す。 |
| 警報の条件から、ほかの警報を参照することはできません。 | 条件の中の `Alarms.*` の参照。 |
| 条件はブール値になる必要がありますが、「x」になりました。 | 条件の試しの評価が、ブール値に変換できない値を返した。 |
| 式のエラー：現在値のポイントは、ここで直接は使えません。.Value のメンバーを通して読んでください（例：Connector.Driver.Device.Tag.Value）。 | 基本の値が必要な場所で実時間のオブジェクトを使った（`Math.round(Variables.Level)`）。 |
| 式のエラー：`<engine message>` | 試しの評価が例外を投げた。知らない識別子、関数として呼んだ届かないメンバーなど。 |

試しの評価は品質にかかわらず今の値で走るので、メッセージが映すのは式であって、悪い入力ではありません。悪い入力のほうは、参照しているポイントのカードに出ます。

## スクリプトの編集画面 {#the-script-editor}

このページの式、条件、スクリプトは、すべて同じカードで編集します。小見出し（式、条件、スクリプト）、**参照…**のボタン、編集画面、助言、そして検証のメッセージです。編集画面は CodeMirror で、JavaScript の色付け、元に戻す履歴、そしてアドレスの語の補完を持ちます。裸の語には最上位の名前、次にそこまで入力した道すじの子、そしてその語がポイントを指したあとはメンバーも出ます（[アドレスを入れる](logic-address-space#entering-an-address)）。文字は少し置いてから下書きに送られ、自動で保存されます。式と条件の入力欄は最低でも 56 px、アクションのスクリプトの入力欄は 160 px の高さです。編集画面のエンジンが動き出せないときは、入力欄はふつうの文字入力の領域に落ちます。読み書きはできますが、色付け、補完、履歴はありません。そのとき参照…は、カーソルの位置ではなく末尾に選んだアドレスを足します。

**参照…**は、アドレス空間の全体のメンバーの段までのツリーを持つダイアログ（「参照：式に挿入」）を開きます。行を選んで**挿入**を押すか、その行をダブルクリックすると、そのアドレスがカーソルの位置に置かれます。編集画面はそれぞれ自分のダイアログを持つので、1 つのページの 2 つの編集画面が選択を共有することはありません。

## 式がしないこと {#what-expressions-do-not-do}

何も書き込みませんし、Process の実行コマンドを呼び出しませんし、評価と評価の間に状態を残しませんし、式どうしで共有する関数を定義できませんし、求められたときに評価されるものでもありません。周期が 100 ms ごとにそれを公開し、編集画面が下書きを 1 秒に 2 回予告します。
