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,43 @@
# Arithmetic Expression
Decodal supports arithmetic over concrete numeric values.
```dcdl
{
workers = 2 + 2;
timeout = 30.0 / 2;
port = 8000 + 80;
negative = -1;
}
```
## Operators
- `+` addition
- `-` subtraction
- `*` multiplication
- `/` division
- unary `-` negation
`*` and `/` bind tighter than `+` and `-`.
Parentheses can be used to make grouping explicit.
```dcdl
2 + 3 * 4 # 14
(2 + 3) * 4 # 20
```
## Numeric behavior
Arithmetic requires concrete `Int` or `Float` operands.
`Int + Int`, `Int - Int`, and `Int * Int` produce `Int` when no overflow occurs.
Mixed `Int` / `Float` arithmetic produces `Float`.
Division always produces `Float`.
Division by zero and integer overflow are evaluation errors.
Arithmetic expressions can be used anywhere a concrete numeric expression is expected, including defaults and numeric constraints.
```dcdl
port = Int & > 4000 + 42 default 8080;
```
@@ -0,0 +1,71 @@
# Array Expression
An array expression represents an ordered sequence of values.
```dcdl
[1, 2, 3]
["a", "b", "c"]
```
An array literal is a concrete value and does not require all elements to have the same type.
```dcdl
["api", 8080, true]
```
## Array constraint
Write an array constraint by placing an ellipsis immediately after `[`, followed by an element constraint.
```dcdl
Names = [...String];
Ports = [...(Int & >= 1 & <= 65535)];
```
`[...T]` represents an array of zero or more elements, all of which satisfy `T`.
An empty array satisfies every array constraint.
```dcdl
[...String] & []
[...String] & ["api", "worker"]
```
The element constraint can be an object range.
A field with a default that exists only on the right remains abstract in every element when the array constraint is composed.
Its default is selected only if the array is later materialized.
```dcdl
Services = [...{
name = String;
enabled = Bool default true;
}];
Services & [{ name = "api"; }]
```
Applying an array constraint to a concrete array refines each element against the element range using the same rules as `as`.
For an object element range, a field present only on the left produces an error, while a field present only on the right remains abstract.
Decodal does not provide an abstract array type without an element constraint.
The former `Array` primitive type is unavailable, and `T` is required in `[...T]`.
`[String]` is not an array constraint; it is a concrete one-element array containing the unresolved `String` constraint.
An array constraint describes only the element range. It has no length, positional tuple, or uniqueness constraints.
## Array concatenation
`++` concatenates two concrete arrays.
```dcdl
base = ["read", "write"];
extra = ["admin"];
roles = base ++ extra;
```
`roles` has the same value as:
```dcdl
["read", "write", "admin"]
```
`++` does not transform array elements.
Elements from the right side follow those from the left.
@@ -0,0 +1,82 @@
# Range Refinement
`narrower as wider` verifies that the left side is more concrete and narrower than the right side, then composes them asymmetrically.
```dcdl
Int & > 10 as Int & > 0
```
This succeeds and returns the narrower left-hand range, `Int & > 10`.
The reverse, `Int as Int & > 0`, fails because the left side is not guaranteed to satisfy the right side.
## Object
For objects, the right side defines the field domain used to check the left:
- A field found only on the left lies outside the right-hand domain and produces an error.
- A field found on both sides is checked recursively, and the narrower left-hand result is used.
- A field found only on the right remains unevaluated in the result, whether or not it has a default.
- Field order in the result follows the right-hand side.
```dcdl
partial = {
port = 8080;
} as {
host = String;
port = Int;
enabled = Bool default true;
};
```
`partial.port` becomes the concrete value `8080`.
`partial.host` and `partial.enabled` remain abstract fields from the right; `as` neither selects nor forces the default for `enabled`.
If `partial` is later materialized, the normal materialization rules apply.
In this example, unresolved `host` produces an error. If `host` is also made concrete, the default for `enabled` is selected during materialization.
## Default
A default is not evidence of range containment.
When the same field exists on both sides, the result uses the left side and does not inject the right-hand default.
```dcdl
Int & > 0 as (Int default 1)
```
The result is `Int & > 0` without a default.
A right-only object field, however, is retained as a whole and therefore retains any default its abstract value already had.
## Map and array ranges
`{...T}` allows arbitrary object keys and verifies that each value is narrower than `T`.
```dcdl
ports = {
http = 80;
https = 443;
} as {...(Int & >= 1 & <= 65535)};
```
When `[...T]` is used on the right, every array element is refined against `T` in the same way.
## Concrete right-hand ranges
Primitive and composed constraints validate values in the usual way.
If the right side is a concrete scalar or array literal, the left must have the same value or the same length and element structure.
A function cannot be used as the right-hand range.
The left side does not have to be concrete.
Abstract values can be used when their containment relation can be determined.
Primitive types, numeric bounds, identical regexes or predicates, and element ranges of arrays and maps support containment checks.
A function parameter written as `name: range` uses the same refinement rules as `as` when its argument is forced.
## Precedence
`as` has the lowest precedence, below `default`, and is left-associative.
```dcdl
narrow & overrides as Wider
```
This is interpreted as `(narrow & overrides) as Wider`.
@@ -0,0 +1,27 @@
# Composition Expression
A composition expression combines multiple values, constraints, or structures.
## `&`
`&` performs constraint-preserving composition.
```dcdl
Port = Int & >= 1 & <= 65535;
Config = MyConfig & { port = 8000; };
```
Because object fields present on only one side are retained, `&` has no direction.
Use [`as`](./ascription.md) to verify that the left side is narrower than the right and treat the right side as the field domain.
## `//`
`//` performs a right-biased structural patch.
```dcdl
Patched = Base // {
feature_hoge.enable = false;
};
```
See [Operators](../operators.md) for details.
@@ -0,0 +1,15 @@
# Default Expression
A `default` expression specifies a fallback selected during materialization when no explicit value exists.
```dcdl
port = Int default 8080;
```
`default` is not a constraint.
See [Constraints and Defaults](../constraints-and-defaults.md) for details.
## Evaluation
The fallback expression is evaluated only if materialization requires it.
When an explicit value exists, the `default` is neither evaluated nor selected.
@@ -0,0 +1,14 @@
# Function Call Expression
A function call expression applies a function value to arguments.
```dcdl
increment(41)
```
## Evaluation
An argument is evaluated when the function body references it.
If the argument is referenced several times, its evaluation result is reused.
When a parameter has a range, the argument is refined using the same rules as `narrower as wider`.
Fields present only in the parameter range remain abstract, and defaults are not selected at this point.
@@ -0,0 +1,14 @@
# Function Expression
A function expression is a value that accepts arguments and returns an expression.
```dcdl
(value: Int) => value + 1
```
See [Functions](../functions.md) for the complete function specification.
## Evaluation
A function can reference bindings from the lexical scope where it was defined.
Its body is evaluated when the function is called, not when the function value is created.
@@ -0,0 +1,14 @@
# Identifier Expression
An identifier expression references a name bound in the lexical scope.
```dcdl
Port
MyConfig
mkConfig
```
## Evaluation
An identifier evaluates the corresponding binding when its value is needed.
If no such binding exists, evaluation produces an unresolved-identifier error.
@@ -0,0 +1,14 @@
# Import Expression
An import expression returns a DCDL module or structured value resolved by the host.
```dcdl
import "./config.dcdl"
```
The specifier is a string literal. The host defines its interpretation as a path, resource name, or another identifier.
See [Modules and Imports](../modules-and-imports.md) for details.
## Evaluation
Imported values are evaluated lazily, and unreferenced fields are not evaluated.
@@ -0,0 +1,26 @@
# Expression
This chapter classifies the expressions evaluated by the language.
An expression is the basic unit for representing a value, constraint, structure, or computation.
```text
Expr
├─ literal
├─ identifier
├─ path reference
├─ object
├─ map constraint
├─ array
├─ array constraint
├─ function
├─ function call
├─ let
├─ match
├─ import
├─ composition
├─ range refinement (`as`)
└─ default
```
Links to each expression specification are collected in the [manual contents](../../index.md).
@@ -0,0 +1,16 @@
# Let Expression
A `let` expression creates local bindings.
```dcdl
let
base = 8000;
offset = 80;
in
base + offset
```
## Evaluation
A binding is evaluated when it is referenced.
An unreferenced binding is not evaluated, and the result is reused if the same binding is referenced several times.
@@ -0,0 +1,20 @@
# Literal Expression
A literal expression is a concrete value written directly in source.
## Kinds
```dcdl
"hello"
123
3.14
true
false
```
## Corresponding primitive types
- A string literal satisfies `String`.
- An integer literal satisfies `Int`.
- A floating-point literal satisfies `Float`.
- `true` and `false` satisfy `Bool`.
@@ -0,0 +1,41 @@
# Logical and Comparison Expressions
Decodal supports boolean logic over concrete `Bool` values and comparison over concrete scalar values.
```dcdl
{
is_prod = env == "prod";
high_port = port > 9000;
enabled = is_prod && high_port;
disabled = !enabled;
}
```
## Logical operators
- `!expr` negates a concrete `Bool`.
- `lhs && rhs` returns boolean AND.
- `lhs || rhs` returns boolean OR.
`&&` and `||` short-circuit: the right-hand side is evaluated only when needed.
Logical operands must evaluate to concrete `Bool` values.
## Comparison operators
- `==`
- `!=`
- `<`
- `<=`
- `>`
- `>=`
`==` and `!=` compare concrete scalar values: `String`, `Bool`, `Int`, and `Float`.
`Int` and `Float` can be compared to each other numerically.
Ordering operators `<`, `<=`, `>`, and `>=` compare concrete numeric values only.
They are separate from prefix comparison constraints such as `> 443`.
```dcdl
port = Int & > 443 default 9443;
is_high = port > 9000;
```
@@ -0,0 +1,24 @@
# Match Expression
A `match` expression compares a target value against patterns from top to bottom and selects the first matching arm.
```dcdl
foo = match inputs.a.hoge {
>= 20: {
value = 200;
};
>= 10: {
value = 100;
};
_: {
value = 300;
};
};
```
`_` is the fallback pattern.
## Ordering
Arms are ordered; Decodal does not automatically select the most specific pattern.
If a broad condition appears first, narrower conditions after it are unreachable.
@@ -0,0 +1,90 @@
# Object Expression
An object expression is a collection of named fields.
```dcdl
{
host = "127.0.0.1";
port = 8000;
}
```
Objects can represent both configuration values and schemas.
```dcdl
MyConfig = {
host = String;
port = Int default 8080;
};
```
## Dot-path fields
A nested field can be defined with a dot path.
```dcdl
{
feature_hoge.enable = false;
}
```
This represents the same structure as:
```dcdl
{
feature_hoge = {
enable = false;
};
}
```
## Map constraint
An associative-array constraint applies the same schema to every field value in an object.
```dcdl
Services = {...{
port = Int;
enabled = Bool default true;
}};
```
`{...T}` represents an object whose keys are not fixed and whose values all satisfy `T`.
An empty object is allowed. After materialization, it becomes the same object data as an object with named fields.
```dcdl
services = {
api = { port = 8080; };
worker = { port = 8081; enabled = false; };
} as Services;
```
Each entry is refined by `as` into the right-hand field domain, so a field other than `port` or `enabled` on the left produces an error.
A field found only on the right remains abstract whether or not it has a default.
An object supplied by the host can preserve string keys that are not valid identifiers, although field names written in DCDL source are limited to ordinary identifiers.
## Object rest constraint
Fixed fields and a value range for arbitrary keys can coexist in one object.
```dcdl
OpenConfig = {
enabled = Bool default true;
...Unknown
};
```
`...T` applies only to remaining fields that were not named explicitly.
Each named field uses its own range; the rest range is not additionally applied to it.
A rest constraint does not generate fields. Materialization outputs only additional fields that actually exist.
```dcdl
{
enabled = false;
plugin = { name = "cache"; };
} as OpenConfig
```
An object can contain one `...T`, at its end.
An object without it is closed, and an undeclared left-hand field under `as` produces an error.
`{...T}` with no named fields is an abstract map constraint; materializing it by itself requires a default or a concrete value.
@@ -0,0 +1,16 @@
# Path Reference Expression
A path reference expression accesses a field of an object.
```dcdl
config.host
config.feature_hoge.enable
```
## Evaluation
The expression on the left is evaluated as an object, then the named field is referenced.
The referenced field is not evaluated until needed.
Referencing a field that does not exist produces a diagnostic.
An explicit `Unknown` range does not represent a missing field, so it does not make field presence ambiguous.