Add bilingual manual and localized docs routes

This commit is contained in:
2026-08-14 11:16:37 +09:00
parent 3645a2cc2d
commit cda32cc260
85 changed files with 2316 additions and 71 deletions
@@ -0,0 +1,163 @@
# Constraints and Defaults
A constraint describes a range that a value must satisfy.
```dcdl
Int
String
>= 1
<= 65535
/Hello! .*/
```
Constraints can be composed with `&`.
```dcdl
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
```
The result is the range that satisfies both sides.
Incompatible constraints produce a conflict.
```dcdl
Int & String # conflict
> 10 & < 5 # conflict
Int & > 10 & < 11 # conflict: integer candidate does not exist
```
## Primitive and comparison constraints
The built-in primitive ranges are:
```dcdl
String
Int
Float
Bool
```
Composing different primitive types with `&` produces a conflict.
Numeric comparison constraints combine as bounds and conflict if they form an empty range.
```dcdl
Int & >= 1 & <= 65535 & > 443
```
Comparison constraints for `Int` use integer literals.
Comparison constraints for `Float` may use either integer or float literals.
## Unknown
`Unknown` is the top range containing every Decodal value.
It is not an `Any` that disables checking and erases concrete information; it means that the value's range has not yet been narrowed.
```dcdl
Int & Unknown # Int
42 as Unknown # 42
Unknown as Int # conflict
```
`Unknown` has no concrete value of its own and therefore cannot be materialized.
It must be narrowed by a concrete value or given a `default`.
```dcdl
Unknown default {}
```
## Regex constraints
A regex literal is a string constraint.
```dcdl
Host = /^api-[0-9]+$/;
```
When several regex constraints are composed, a concrete string must match all of them.
```dcdl
String & /^a/ & /z$/
```
The intersection of regex constraints is not determined during composition.
The following range therefore does not conflict when composed, but fails when a concrete value is validated.
```dcdl
String & /^a$/ & /^b$/
```
In the Rust runtime, enable the regex engine with the `regex` feature.
Without that feature, validating a regex constraint against a concrete value produces an unsupported-feature diagnostic.
## Array constraints
Write an array constraint as `[...T]`; it applies `T` to every element.
The element constraint is required.
```dcdl
Names = [...String];
PositiveInts = [...(Int & > 0)];
```
When composed with a concrete array, each element is refined against `T` using the same rules as `as`.
An empty array satisfies every array constraint.
If the element constraint is an object range, fields present only on the right remain abstract in every element.
A field present only on the left is outside the right-hand field domain and produces a conflict.
## Associative-array and object rest constraints
Write an associative-array constraint as `{...T}`; it applies `T` to every field value in an object.
```dcdl
Services = {...{
port = Int;
enabled = Bool default true;
}};
```
Keys are not enumerated, and an empty object is allowed.
Writing `...T` at the end of an object with named fields applies `T` only to fields that were not named explicitly.
```dcdl
{
enabled = Bool default true;
...Unknown
}
```
A rest constraint does not generate fields.
It only validates additional fields that actually exist.
## default
`default` is not a constraint.
It is a fallback used only when no concrete value exists during materialization.
```dcdl
Port = Int & >= 1 & <= 65535;
Service = {
port = Port default 8080;
};
```
When an explicit value has been composed into the range, that value is used and `default` is not evaluated.
```dcdl
Config = {
port = 9000;
} as Service;
```
Without an explicit value, materialization selects `8080` and verifies that it satisfies `Port`.
## Default composition
- If only one side of `&` has a `default`, that `default` is preserved.
- If both sides of `&` have different defaults, they conflict.
- If `&` between a constraint and a concrete value succeeds, the result is concrete and does not retain the `default`.
- Because `//` is right-biased, the right-hand value or `default` replaces the left-hand one for the same field.
- `as` does not inject a right-hand `default` into the left side. A field that exists only on the right, however, remains abstract in the result together with its `default`.
A `default` expression is evaluated when materialization requires it and must satisfy the constraints of the same range.