Files
Decodal/doc/manual/source/jp/language/constraints-and-defaults.md
T

164 lines
4.6 KiB
Markdown

# 制約と default
constraint は、値が満たすべき範囲を表す。
```dcdl
Int
String
>= 1
<= 65535
/Hello! .*/
```
constraint は `&` で合成できる。
```dcdl
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
```
合成結果は両辺を同時に満たす範囲になる。
両立しない constraint は conflict になる。
```dcdl
Int & String # conflict
> 10 & < 5 # conflict
Int & > 10 & < 11 # conflict: integer candidate does not exist
```
## Primitive and comparison constraints
組み込みの primitive range は次の通りである。
```dcdl
String
Int
Float
Bool
```
異なる primitive type を `&` で合成すると conflict になる。
数値比較 constraint は上下限として合成され、空の範囲になる場合は conflict になる。
```dcdl
Int & >= 1 & <= 65535 & > 443
```
`Int` の比較 constraint は integer literal を使う。
`Float` の比較 constraint は integer または float literal を使える。
## Unknown
`Unknown` はすべての Decodal value を含む最上位 range である。
検査を無効化して具体値の情報を消す `Any` ではなく、値の範囲がまだ絞られていないことを表す。
```dcdl
Int & Unknown # Int
42 as Unknown # 42
Unknown as Int # conflict
```
`Unknown` 自体は concrete value を持たないため materialize できない。
concrete value で絞り込むか `default` を指定する必要がある。
```dcdl
Unknown default {}
```
## Regex constraints
regex literal は string constraint である。
```dcdl
Host = /^api-[0-9]+$/;
```
複数の regex constraint を合成した場合、concrete string はすべてに一致する必要がある。
```dcdl
String & /^a/ & /z$/
```
regex constraint 同士の交差は合成時には判定されない。
そのため、次の範囲は合成時には conflict にならず、concrete value の検証時に失敗する。
```dcdl
String & /^a$/ & /^b$/
```
Rust runtime では regex engine を `regex` feature で有効にする。
feature が無効な場合、regex constraint の concrete value 検証は unsupported feature diagnostic になる。
## Array constraints
array constraint は `[...T]` と書き、すべての要素へ `T` を適用する。
要素 constraint は必須である。
```dcdl
Names = [...String];
PositiveInts = [...(Int & > 0)];
```
concrete array と合成した場合、各要素は `T` に対して `as` と同じ規則で絞り込まれる。
空 array は任意の array constraint を満たす。
要素 constraint が object range の場合、右辺にだけある field は abstract のまま各要素へ残る。
左辺にしかない field は右辺の field domain 外なので conflict になる。
## Associative-array and object rest constraints
associative-array constraint は `{...T}` と書き、object の任意の field value へ `T` を適用する。
```dcdl
Services = {...{
port = Int;
enabled = Bool default true;
}};
```
key は列挙されず、空 object も許容される。
named field を持つ object の末尾へ `...T` を書くと、列挙されていない field だけに `T` を適用できる。
```dcdl
{
enabled = Bool default true;
...Unknown
}
```
rest constraint は field を生成しない。
実在する追加 field の検証にだけ使われる。
## default
`default` は constraint ではない。
materialize 時に concrete value がない場合だけ使われる fallback である。
```dcdl
Port = Int & >= 1 & <= 65535;
Service = {
port = Port default 8080;
};
```
明示値が合成された場合は明示値が使われ、`default` は評価されない。
```dcdl
Config = {
port = 9000;
} as Service;
```
明示値がない場合、materialize 時に `8080` が採用され、`Port` を満たすか検証される。
## default composition
- `&` で片方だけが `default` を持つ場合、その `default` は保持される。
- `&` で両辺が異なる `default` を持つ場合は conflict になる。
- constraint と concrete value の `&` が成功した場合、結果は concrete value になり `default` は残らない。
- `//` は右辺優先なので、同じ field では右辺の値または `default` が左辺を置き換える。
- `as` は右辺の `default` を左辺へ注入しない。ただし右辺にだけ存在する field は、その field が持つ `default` とともに abstract なまま結果へ残る。
`default` expression は materialize 時に必要になった時点で評価され、同じ range の constraint を満たす必要がある。