関数フィールド
Related information
はじめに
関数 DSL (ドメイン固有言語) を使用して、関数フィールドを定義します。
この DSL は、手続き型で静的に型付けされた言語です。
関数フィールドを作成および変更するには、Data Model Assistant (DMA) を使用します。
データモデルアシスタント (DMA) には、コンテキストコードの補完を提供するスクリプトエディターが含まれています。
字句構造
はじめに
スクリプトの構造は次のとおりです。
<unit usage statement 1>
<unit usage statement 2>
...
<unit usage statement N>
<function or procedure definition 1>
<function or procedure definition 2>
...
<function or procedure definition M>
例
// This field returns the full address for current record.
export function getValue(): string
begin
var address := record.FirstName | ' ' | record.LastName;
for street in record.OfficeAddress.Street do
begin
address |= '\n' | street;
end;
address |= '\n' | record.OfficeAddress.ZipCode | ' ' | record.OfficeAddress.City;
address |= '\n' | record.OfficeAddress.Country;
return address;
end
文字セット
Unicode 文字セットがサポートされています。
文字の大文字と小文字の区別
DSL では大文字と小文字が区別されます。
コメント
1 行のコメントは、**//**から現在の行の終わりまで拡張されます。
// This is a comment
if record.LastName = 'Doe' then // This is another comment.
return true;
複数行のコメントは **/***から始まり、 */ で終わります。
/* This is an example of a multi-line
comment */
if record.isActive then
return false;
キーワード
予約済みのキーワードは、 and、** or**、** not**、** uses**、** as**、** export**、** typeof**、** mutable**、** immutable**、** unmodifiable**、** function**、** procedure**、** const**、** var**、** if**、** then**、** else**、** for**、** while**、** in**、 do、** begin**、** end**、** return**、** true**、** false**、** null** です。
予約済みのキーワードは、プレーンな (引用符で囲まれていない) 識別子として使用することはできません。
識別子
引用符なしの識別子
引用符なしの識別子 は、文字、数字、またはアンダースコア (\_) の無制限の長さのシーケンスです。最初の文字は、文字またはアンダースコアにする必要があります。
有効な文字は a から z および A から Z です。有効な数字は 0 から 9 です。
引用符なしの識別子は、予約済みのキーワードと等しくない場合があります。
引用符付きの識別子
引用符付き識別子は、二重引用符 (")を除く任意の Unicode 文字の無制限の長さです。
引用符で囲まれた識別子は、二重引用符で囲んで使用する必要があります。
引用符なしの識別子は、二重引用符で囲んで使用できます。これは、識別子「a\_name」が a\_name と等しいことを意味します。
引用符付きの識別子は予約済みのキーワードにすることができます。
型
単純型
次の単純な型がサポートされています。
| タイプ | キーワード | プロパティ | EBX® 対応型 |
|---|---|---|---|
| ブール値 | boolean | xs:boolean | |
| 10 進数 (無制限の精度) | decimal | xs:decimal | |
| 整数 (32ビット) | int | xs:int xs:integer | |
| 文字列 | string | xs:string xs:Name osd:text osd:html osd:email osd:password 1 osd:color osd:dataspaceKey osd:datasetName | |
| タイムスタンプ (ミリ秒の精度でタイムゾーンなし) | timestamp | 年 月 (1 から 12) 日 (1 から 31) 時間 (0 から 23) 分 (0 から 59) 秒 (0.000 から 59.999) | xs:dateTime |
| 日付 (タイムゾーンなし) | date | 年 月 (1 から 12) 日 (1 から 31) | xs:date |
| 時間 (ミリ秒の精度) | time | 時間 (0 から 23) 分 (0 から 59) 秒 (0.000 から 59.999) | xs:time |
| ロケール | locale | osd:locale | |
| URI (Uniform Resource Identifier) | uri | xs:anyURI | |
| リソース | resource | osd:resource |
1 タイプ osd:password の関数フィールドを定義することはできません。
複合型
複合型は、EBX® スキーマで定義されたグループ (複合) ノードの型です。
詳細については、複合型の変数の章を参照してください。
スキーマノードの型への参照 (たとえば、関数パラメーターまたは変数を宣言するとき) は、 keyword typeof の使用を意味します。
リスト型
DSL はリストをサポートしています。次の構文を使用してリストを宣言します。
list<item_type>
次の構文を使用して、変更不可能なリストを宣言します。
unmodifiable list<item_type>
リストが変更できない場合、項目を追加、削除、または置き換えることはできません。リストの項目は、その型に応じて、変更できる場合とできない場合があります。
インデックス付き表記を使用して、値を設定または取得します (最初のインデックスは 0)。
// Set first value of cities.
cities[0] := 'Paris';
// Get the second item of cities.
return cities[1];
インデックスは、10 進型の任意の式にすることができます。小数部分を削除して、インデックス値を整数に変換します。
インデックスが null、負の値、または範囲外の場合、get 式は null を返します。
インデックスが null、負の値、または範囲外の場合、set 式は実行時にエラーを報告します。
プロパティ size は、リストのサイズを返します。
var size := cities.size;
リストを反復できます。詳細については、for ループを参照してください。
複数値スキーマフィールド
複数値のスキーマフィールドは、リスト型と見なされます。
複数値スキーマフィールドは、値の最大数 (maxOccurs) が 1 より大きいか、「unbounded」に設定されているフィールドです。
インデックス付き表記は、値にアクセスまたは設定するために使用されます。最初のインデックスは 0 です。次の例では、レコードフィールド「OfficeAddress/street」は複数値です。
// Return the second line of the street part of the address.
return OfficeAddress.street[1].
typeof キーワードは、多値フィールドで使用できます (keyword typeof の章を参照)。
可変型と不変型
不変の複合型またはリストオブジェクトを変更することはできません。
可変複合型またはリストオブジェクトを変更できますが、オブジェクトの一部の属性の変更を妨げる可能性のある他の制約が適用される場合があります。
単純型は常に不変です。
変数または互換性のある不変型の戻り値に可変値を割り当てることができますが、不変値を可変変数または戻り値に割り当てると、コンパイル時にエラーが発生します。
typeof キーワード
フィールドまたは変数に応じて型を指定するには、キーワード typeof を使用します。このキーワードは、キーワード mutable または immutable の後に使用できます。
たとえば、レコードフィールド OfficeAddress の型を参照するには、次の構文を使用します。
typeof record.OfficeAddress
デフォルトでは、レコードフィールドの型は常に不変です。次の構文を使用して、可変型を指定できます。
mutable typeof record.OfficeAddress
フィールドが複数値の場合、リストと見なされます。次の構文を使用して、リストの項目の型を参照できます。
typeof record.Addresses[*]
可変形式の型では、キーワード「mutable」を使用できます。
mutable typeof record.Addresses[*]
型に変更可能な形式がない場合、キーワードは単に無視されます。これは単純な型の場合です。
===
リテラル
文字列リテラル
文字列リテラルは、一重引用符で囲まれた Unicode 文字の任意のシーケンスにすることができます。次の表は、エスケープシーケンスで置き換える必要のある文字を示しています。
| 文字 | エスケープシーケンス |
|---|---|
| タブ | \t |
| バックスペース | \b |
| 改行 | \n |
| キャリッジリターン | \r |
| フォームフィード | \f |
| 一重引用符 | \' |
| バックラッシュ | \\ |
\uXXXX 形式の Unicode エスケープシーケンスを使用して文字を指定します。XXXX は Unicode 文字の 16 進数コードです。
例
| 値 | 構文 |
|---|---|
| O’Harra | 'O\'Harra' |
| Noël | 'No\u00EBl' |
| été | '\u00e9\u00E9' |
注意
無効なエスケープまたは Unicode シーケンスは、コンパイル時にエラーを生成します。
10 進数または整数のリテラル
次の 10 進形式がサポートされています。
| 形式 | 例 |
|---|---|
| 整数 | 546 -67 |
| 浮動小数点数 | 54.987 -433.876 0.00054 -0.0032 |
| 指数表記 | 34.654e-5 -45E+65 1.543e23 |
タイムスタンプリテラル
タイムスタンプ リテラルの形式は dt(yyyy-MM-dd hh:mm:ss.sss) です。
秒はオプションです。指定されていない場合は 0 と見なされます。秒は、ミリ秒の精度までの小数部を持つことができます。
グレゴリオ暦で無効な日付は、コンパイル時にエラーを生成します。
例
dt(2010-01-02 00:00:00.000)
dt(2019-2-3 12:56:7)
dt(2019-2-3 12:56:7.5)
dt(2019-5-7 1:6)
日付リテラル
日付リテラルの形式は d(yyyy-MM-dd) です。
グレゴリオ暦で無効な日付は、コンパイル時にエラーを生成します。
例
d(2010-01-02)
d(2019-2-3)
dt(2019-5-7)
時間リテラル
時間リテラルの形式は t(hh:mm:ss.sss) です。
秒はオプションです。指定されていない場合は 0 と見なされます。秒は、ミリ秒の精度までの小数部を持つことができます。
無効な時間は、コンパイル時にエラーを生成します。
例
t(00:00:00)
t(12:56:7)
t(12:56:7.5)
t(1:6)
ブール値リテラル
ブール値リテラルは、キーワード true またはキーワード false のいずれかです。
Null リテラル
null リテラルはキーワード null です。
このリテラルは、次の状況でのみ使用してください。
-
変数またはフィールドを設定する
-
戻り値
注意
このキーワードを使用して、変数またはフィールドが null かどうかをテストすることはできません。代わりに、関数 isNull() を使用してください。
演算子
優先順位
デフォルトでは、操作の評価順序は優先順位と結合性に基づいています。括弧を使用して、評価の順序を明示的に示します。
次の表は、優先順位の高いものから低いものへのすべての演算子と、それらの関連性を示しています。
算術演算子
すべての算術演算子 ( *、/ 、+ および - ) は、34 桁の精度 (IEEE 754R Decimal128 形式)。いずれかのオペランドが null の場合、結果は null になります。
int 型変数に割り当てられると、10 進値は自動的に変換されます。値が整数ではない、2147483647 より大きい、または-2147483648 より小さいために値を変換できない場合、エラーが発生します。
文字列連結演算子
文字列連結演算子 ( | ) オペランドは任意の型にすることができ、連結前に自動的に文字列に変換されます。** null** 値は空の文字列に置き換えられます。
文字列連結演算子 ( | ) は、連結を実行する前に、すべての null オペランドを空の文字列に置き換えます。
ブール演算子
ブール演算子はスレッド値ロジックを使用します。
AND 演算子の真偽 (true/false) 表は次のとおりです。
| And | true | false | null |
|---|---|---|---|
| true | true | false | null |
| false | false | false | false |
| null | null | false | null |
OR 演算子の真偽 (true/false) 表は次のとおりです。
| Or | true | false | null |
|---|---|---|---|
| true | true | true | true |
| false | true | false | null |
| null | true | null | null |
比較演算子
比較演算子 ( < ,<= ,> ,=> ,= and <> ) は、同じ型の 2 つのオペランドを比較します。int 型の変数は、比較前に常に 10 進数に変換されます。
コンパレータの戻り値は boolean 型です。すべてのオペランドが null でない場合のみ、この値は true または false になります。オペランドのいずれかが null の場合、それは null です。
ビルトインおよびユニット機能
ビルトイン関数とユニット関数は通常、パラメーターが null の場合、 null を返します。
例外もあるため、必ず API ドキュメント を参照してください。
割り当て
次の表に、すべての割り当て演算子を示します。
| 演算子 | オペランド型 | 説明 |
|---|---|---|
| := | あらゆる型に使用できます。 | 標準割り当て。 |
| = | 文字列 | |
| += | 10 進数 | a += b は a:= a + bと同等 |
| -= | 10 進数 | a-= b は a := a-b と同等 |
| *= | 10 進数 | a *= b は a := a * b と同等 |
| /= | 10 進数 | a /= b は a := a / b と同等 |
ステートメントブロック
ステートメント ブロックは、複数のステートメントをグループ化するために使用されます。キーワード begin で始まり、キーワード end で終わります。ほとんどのステートメントは ; で終了する必要があります。
begin
statement_1;
statement_2;
end
ステートメントブロックには、ステートメントブロックを含めることもできる 1 つ以上のステートメントブロックを含めることができます。
begin
statement_1;
begin
statement_2_1;
statement_2_3;
begin
statement_3_1;
statement_3_2;
end
end
statement_3;
end
変数と定数
はじめに
ブロック内の任意のステートメントは、変数または定数を宣言できます。
変数または定数の型は常に、変数が宣言されたときに固定されます。
代入演算子 := を使用して、値を変数に割り当てることができます。
間違った型の値を変数に割り当てたり、宣言後に定数の値を変更したりすると、エラーになります。
割り当てステートメント
型検出による宣言
変数または定数型は、宣言時に初期化すると自動的に検出できます。この機能は型推論と呼ばれます。
変数の構文は次のとおりです。
var variable_name := a_value;
定数の構文は次のとおりです。
const const_name := a_value;
例
begin
var firstName := 'John'; // Variable of type string.
var age := 30; // Variable of type decimal.
var address := record.address; // Variable of an immutable complex.
const MAX_AGE := 100; // Decimal constant.
const DEFAULT_COUNTRY := 'France'; // String constant.
end
注意
定数は必ずしも不変ではありません。
明示的な型定義
変数の型を明示的に指定することができます。
変数の構文は次のとおりです。
// Following variable initial value is null.
var variable_1_name : variable_1_type;
// Value a_value must be compatible with type variable_1_type.
var variable_2_name : variable_1_type := a_value;
定数の構文は次のとおりです。
const const_name : variable_1_type := a_value;
例
begin
var firstName : string;
firstName := 'John';
var age : decimal;
age := 30;
var address : typeof record.address;
address := record.address;
const MAX_AGE : decimal := 100;
const DEFAULT_COUNTRY : string := 'France';
end
初期化されていない変数の値は null です。
begin
var firstName : string;
if isNull(fistName) then
do_something(); // Statement will be executed.
end
次のステートメントにはエラーがあります。
begin
// Following will not compile because variable is not initialized and no type
// is defined.
var firstName;
// Following will not compile because variable type is decimal and value is
// a string.
var age : decimal := 'test';
end
範囲
変数または定数範囲は、その宣言から、宣言されたステートメントブロックの終わりまでに及びます。
begin
var firstName := 'John';
var lastName := 'Doe';
begin
// Following is OK because firstName and lastName are visible.
var fullName := firstName | ' ' | lastName;
....
end
// Following will NOT compile because fullName is out of the scope.
var message := 'Please contact ' | fullName;
end
同じ名前の変数を同じブロックまたはサブブロックに存在させることはできません。
begin
var firstName := 'John';
begin
var firstName := 'Bob'; // Error! Variable already declared.
....
end
end
以下は正しい記述です。
begin
begin
var firstName := 'Bob';
....
end
// The following is not an error, because block where previous variable was
// declared is ended.
var firstName := 'John';
end
複合型変数
複合型の変数または定数は、型検出または typeof キーワードを使用して宣言できます。
ドット表記は、複合型の変数のフィールドにアクセスするために使用されます。
例
// Declaration using type detection.
var address1 := record.OfficeAddress;
// Declaration using typeof notation.
var address2 : typeof record.OfficeAddress;
address2 := address1;
各ステップ (ドットで区切られた部分) は 識別子です。これは、次の引用表記をどのステップにも使用できることを意味します。
var city := record."OfficeAddress".City;
これは、予約済みのキーワードに相当するステップや、マイナス文字 ( - ) やドット ( . )などの引用符で囲まれていない識別子と互換性のない文字を使用するステップに役立ちます。
実行時に、どのステップも null と評価される可能性があります。この場合、完全なフィールド式は null と評価されます。
複数値フィールド
事前定義された変数
はじめに
事前定義された変数により、コンテキストへのアクセスが可能になります。これらのコンテキスト変数は定数であり、不変の複合型です。
レコード
事前定義された変数 record は、現在のスクリプトがテーブルの関数フィールド用である場合にのみ使用できます。現在のレコードへの読み取り専用アクセスを許可します。
そのフィールドは、現在の EBX® スキーマによって定義されています。
例
// Returns the full name.
export function getValue(): string
begin
return record.FirstName | ' ' | record.LastName;
end
ルート
事前定義された変数 root は、現在のスクリプトがデータセットの関数インスタンスフィールド用である場合にのみ使用できます。現在のデータセットのインスタンスフィールドへの読み取り専用アクセスを提供します。
そのフィールドは、現在の EBX® スキーマによって定義されています。
例
// Returns information on current dataset data.
export function getValue(): string
begin
return root.City | ' ' | root.Region;
end
データスペース
事前定義された変数 dataspace は、現在のデータスペースに関する情報へのアクセスを提供します。
この変数には次のフィールドがあります。
| 名前 | タイプ | 説明 |
|---|---|---|
| name | 文字列 | データスペースの名前。データスペースの名前空間とスナップショットの名前空間は独立しているため、返される文字列は名前空間の 1 つのコンテキストにおける識別子にすぎません。グローバル データスペースまたはスナップショット識別子には、フィールド id を使用します。 |
| id | 文字列 | データスペースまたはスナップショットの永続的な識別子。** name** と比較すると、この識別子は、この ID がデータスペース用かスナップショット用かをさらに指定します。 |
| isSnapshot | ブール値 | データスペースがスナップショットの場合は true であり、データスペースがブランチの場合は false です。 |
例
// Returns details on the current dataspace.
export function getValue(): string
begin
if dataspace.isSnapshot then
return 'Snapshot: ' | dataspace.name;
else
return 'Branch: ' | dataspace.name;
end
データセット
事前定義された変数 dataset は、現在のデータセットに関する情報へのアクセスを提供します。
この変数には次のフィールドがあります。
| 名前 | タイプ | 説明 |
|---|---|---|
| name | 文字列 | データセットの名前 |
例
// Returns the current dataset name.
export function getValue(): string
begin
return dataset.name;
end
関数とプロシージャ
関数
関数は、値を返すメソッドです。
パラメーターのない関数の構文は次のとおりです。
function function_name(): return_value_type
begin
....
return a_value;
end
パラメーターを使用する関数の構文は次のとおりです。
function function_name(
parameter_1 : parameter_1_type,
parameter_2 : parameter_2_type...): return_value_type
begin
....
return a_value;
end
関数の最後のステートメントは常に return ステートメントにする必要があります。この関数には、必要な数の return ステートメントを含めることができます。
例
function getFullName(firstName: string, lastName: string): string
begin
if isNull(firstName) then
return lastName;
return firstName | ' ' | lastName;
end
宣言された値とは異なる値を返すことは違法です。
function getValue(): string
begin
return 0; // Error! Return type is decimal, not string.
end
エクスポートされた関数
エクスポートされた関数は、EBX® から直接呼び出すことができます。
スクリプトごとに許可されるエクスポートされた関数は 1 つだけです。そのシグネチャ (名前、および戻り型) は、関数フィールドの型によって異なります。
レコードのフィールドの場合、定義は次のようにする必要があります。
export function getValue(): typeof record.<path>
begin
...
end
データセットのフィールドの場合、定義は次のようにする必要があります。
export function getValue(): typeof root.<path>
begin
...
end
関数フィールドが最初に編集される場合、EBX® はエクスポートされた関数の正しい定義を備えた初期スクリプトを提供します。
プロシージャ
プロシージャは、値を返さないメソッドです。
パラメーターのないプロシージャの構文は次のとおりです。
procedure procedure_name()
begin
....
end
パラメーターを使用するプロシージャの構文は次のとおりです。
procedure procedure_name(
parameter_1 : parameter_1_type,
parameter_2 : parameter_2_type...)
begin
....
end
プロシージャに return ステートメントを含めることはできませんが、関数には必要な数の return ステートメントを含めることができます。プロシージャステートメントは値を返すことができません。
パラメーター
単純型パラメーターは値によって渡されます。これは、関数またはプロシージャが元の値のコピーを受け取ることを意味します。
複合型とリスト型は参照によって渡されます。これは、関数またはプロシージャが元のオブジェクトを受け取ることを意味します。関数またはプロシージャがオブジェクトを変更すると、元のオブジェクトが変更されます。
If ステートメント
「If then」ステートメント
「if then」ステートメントの構文は次のとおりです。
if condition-expression then
then-statement
条件式はブール型として評価される必要があります。
「then」ステートメントは ステートメントブロックにすることができます。
「If then else」ステートメント
「if then else」ステートメントの構文は次のとおりです。
if condition-expression then
then-statement
else
else-statement
条件式はブール型にする必要があります。
「then」または「else」ステートメントは、ステートメントブロックにすることができます。
注意
式
if condition-expression then
statements-a;
else
statements-b;
次のように指定することはできません。
if not condition-expression then
statements-b;
else
statements-a;
実際、式が null の場合、どちらの場合も else ステートメントが実行されます。
ループ
「For in do」ループ
「for in do」ループステートメントは、リストの各項目を選択し、ブロックステートメントを実行するために使用されます。構文は次のとおりです。
for item_variable_name in list do
begin
statement_a;
statement_b;
...
end
ブロックステートメントは、リストの値ごとに 1 回実行されます。各反復で、読み取り専用アイテム変数は、リストの順序でリストの値を取ります。
item 変数の名前は、現在の範囲内で一意にする必要があります。一意でない場合、コンパイル時にエラーが生成されます。
項目ごとに 1 つのステートメントを実行する必要がある場合は、次のより単純な構文を使用できます。
for item_variable_name in list do statement;
次の例は、複合体のリストを繰り返します。
// Concatenate all city addresses in a single string.
var cities := '';
for address in record.Addresses do
begin
if cities <> '' then cities |= ', ';
cities |= address.city;
end
「While do」ループ
「while do」ループステートメントは、条件が true になるまでステートメントブロックを実行するために使用されます。次の構文があります。
while condition do
begin
statement_a;
statement_b;
...
end
単一のステートメントを実行する必要がある場合は、より単純な、次の構文を使用できます。
while condition do statement_a;
次の例では、値の階乗を計算します。
function factorial(value : decimal): decimal
begin
var factorial := value;
while(value > 1) do
begin
value -= 1;
factorial *= value;
end
return factorial;
end
ユニット
EBX® は、「ユニット」にパッケージ化された API を提供します。
ユニットは、複数の機能またはプロシージャを定義できます。
デフォルトのものを除いて、「Unit」は使用前に宣言する必要があります。宣言はスクリプトの先頭にあり、次の型の構文に従う必要があります。
uses package_name.unit_name_a;
uses package_name.unit_name_b as alias_b;
現在、** package\_name** は常に core です。ユニットエイリアスは、スクリプト内で一意にする必要があります。
メソッドは、次の構文を使用して参照できます。
value1 := package_name.unit_name_a.function_a();
value2 := package_name.unit_name_a.function_b(parameter1, parameter2);
value3 := alias_a.function_c();
value4 := alias_a.function_d(parameter1, parameter2);
package_name.unit_name_a.procedure_a();
package_name.unit_name_a.procedure_b(parameter1, parameter2);
alias_a.procedure_c();
alias_a.procedure_d(parameter1, parameter2);
次の例では、** core.list** ユニットを使用してリストを作成します。
uses core.list as list;
export function getValue(): typeof record.Cities
begin
return list.of('Paris', 'Bruxelles', 'Berlin');
end
提供されているユニットの詳細については、API ドキュメントを参照してください。
ログ取得とデバッグ
ユニット unit.log は、メッセージをログに記録するために使用できる関数を提供します。
もう 1 つの便利な機能は、スクリプトの実行中にランタイムでエラーが発生した場合、通常、エラーが発生したスクリプトの行とともにログに記録されることです。
初期スクリプト
DMA を使用して新しい関数フィールドが作成されると、初期スクリプトが作成されます。
次の例は、文字列型のフィールド用に作成されたスクリプトです。
export function getValue(): string
begin
return 'A string value';
end
エクスポートされた関数シグネチャ (名前と戻り値の型) はフィールドの型によって異なるため、変更しないでください。