This commit is contained in:
Keisuke Hirata 2026-06-16 01:27:54 +09:00
parent 5d6a03b74f
commit 4e82f47f90
No known key found for this signature in database
31 changed files with 141 additions and 112 deletions

View File

@ -1,6 +1,7 @@
# Manual
# Decodal Manual
このディレクトリには、マニュアル文書を置く。
このディレクトリには、Decodal のマニュアル文書を置く。
Decodal は Deferred Constraint Data Language、略称 DCDL のプロジェクト名である。
## 目次
@ -34,4 +35,10 @@
9. [Materialization and Errors](./language/materialization-and-errors.md)
10. [Naming Conventions](./language/naming.md)
11. [Examples](./language/examples.md)
3. [Open Issues](./open-issues.md)
3. [Implementation Design](./design/index.md)
1. [Execution Pipeline](./design/execution-pipeline.md)
2. [Runtime Model](./design/runtime-model.md)
3. [Thunk and Lazy Evaluation](./design/thunk-and-lazy-evaluation.md)
4. [Composition and Materialization](./design/composition-and-materialization.md)
5. [Diagnostics and Fallback](./design/diagnostics-and-fallback.md)
4. [Open Issues](./open-issues.md)

View File

@ -1,7 +1,10 @@
# Introduction
このマニュアルは、遅延評価データ記述言語の目的、設計方針、言語仕様をまとめる。
この言語は、設定値・スキーマ・制約・派生設定を同じ式体系で扱い、組み込み環境でも実装しやすい小さな言語核を提供することを目指す。
このマニュアルは、Decodal の目的、設計方針、言語仕様をまとめる。
Decodal は **Deferred Constraint Data Language**、略称 **DCDL** のプロジェクト名である。
ファイル拡張子は `.dcdl` とする。
Decodal は、設定値・スキーマ・制約・派生設定を同じ式体系で扱い、組み込み環境でも実装しやすい小さな言語核を提供することを目指す。
## 目的
@ -10,7 +13,7 @@
例えば、以下のように制約と値を同じ構文で合成できる。
```n
```dcdl
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
@ -47,7 +50,7 @@ Config = MyConfig & {
- 到達不能分岐の静的検査。
- 任意の関数呼び出し結果のグローバル memoize。
- 正規表現エンジンの必須搭載。
- `try / catch` の必須搭載。
- 汎用 `try / catch` の core 搭載。
- 完全なプログラミング言語としての汎用性。
## 中心概念
@ -74,6 +77,9 @@ Config = MyConfig & {
言語仕様の解説は [Language Specification](./language/index.md) にまとめる。
`language/` 配下には、構文、値、式、制約、演算子、評価意味論など、言語仕様そのものの説明だけを置く。
処理系の設計は [Implementation Design](./design/index.md) にまとめる。
ここでは、AST interpreter、runtime value、thunk、合成処理、materialize、diagnostic の扱いを説明する。
主な章は以下である。
- [Value](./language/value/index.md): `String`、`Int`、`Float`、`Bool` などの値・プリミティブ制約。
@ -82,5 +88,7 @@ Config = MyConfig & {
- [Composition Operators](./language/operators.md): `&``//` の意味。
- [Evaluation Semantics](./language/evaluation.md): 遅延評価、thunk、循環検出。
- [Materialization and Errors](./language/materialization-and-errors.md): 最終評価とエラー分類。
- [Runtime Model](./design/runtime-model.md): concrete value と abstract value の内部表現。
- [Thunk and Lazy Evaluation](./design/thunk-and-lazy-evaluation.md): 遅延計算と循環検出の処理系モデル。
未確定事項は [Open Issues](./open-issues.md) に集約する。

View File

@ -6,7 +6,7 @@
制約は、値が満たすべき条件を表す。
```n
```dcdl
Int
String
>= 1
@ -16,7 +16,7 @@ String
制約は `&` により合成できる。
```n
```dcdl
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
```
@ -29,7 +29,7 @@ A & B = A と B の両方を満たす値または制約
矛盾する制約はエラーになる。
```n
```dcdl
Int & String # エラー
>= 10 & <= 5 # エラーになりうる
```
@ -38,7 +38,7 @@ Int & String # エラー
最小の組み込み制約は以下である。
```n
```dcdl
String
Int
Float
@ -47,7 +47,7 @@ Bool
追加の述語制約はライブラリまたは組み込みとして提供できる。
```n
```dcdl
IPv4Address
```
@ -55,14 +55,14 @@ IPv4Address
正規表現リテラルは文字列制約として使える候補である。
```n
```dcdl
Host = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
```
ただし、組み込み向け実装では正規表現エンジンを optional feature にできる。
軽量実装では代表的な制約を組み込み述語として提供してもよい。
```n
```dcdl
Host = IPv4Address;
```
@ -71,21 +71,22 @@ Host = IPv4Address;
`default` は制約ではない。
`default` は、最終評価時に明示値が存在しない場合だけ使われる fallback 値である。
```n
```dcdl
port = NarrowedPort default 8080;
```
これは概念的には以下を表す。
```text
constraint = NarrowedPort
value = none
default = 8080
Abstract {
constraints: [NarrowedPort]
default: 8080
}
```
明示値が合成された場合、`default` は採用されない。
```n
```dcdl
MyConfig = {
port = NarrowedPort default 8080;
};
@ -102,26 +103,31 @@ Config = MyConfig & {
採用された default 値は、同じフィールドに定義された制約を満たす必要がある。
```text
constraint = NarrowedPort
value = none
default = 8080
Abstract {
constraints: [NarrowedPort]
default: 8080
}
finalize => 8080 が NarrowedPort を満たせば成功
```
## default の内部表現
`default` は fallback thunk として保持できる。
`default`abstract value に付随する fallback thunk として保持できる。
これにより、default 値自体も必要になるまで評価しない。
```text
Cell {
constraint: ConstraintSet
value: Option<Value>
default: Option<Thunk>
}
RuntimeValue =
Concrete(ConcreteValue)
Abstract {
constraints: Vec<Constraint>
default: Option<Thunk>
}
```
明示値は `Concrete` として表現し、`default` を保持しない。
`Abstract & Concrete` が成功した場合、制約検証後に `Concrete` になり、default は消える。
## default の合成
同じフィールドに複数の `default` が合成された場合の詳細規則は未確定である。

View File

@ -4,7 +4,7 @@
## 基本方針
```n
```dcdl
{
schema = {
hoge = String;
@ -46,7 +46,7 @@ Error 評価失敗
## 循環検出
```n
```dcdl
{
a = b + 1;
b = a + 1;

View File

@ -4,7 +4,7 @@
## 基本的な設定スキーマ
```n
```dcdl
rec {
Host = IPv4Address;
@ -35,7 +35,7 @@ enabled_config = NewConfig;
## 関数と文字列生成
```n
```dcdl
let
maybe_hw = String & /Hello! .*/;
part = {
@ -59,7 +59,7 @@ in
## match
```n
```dcdl
(
input_a: {
hoge = Int & >= 0;
@ -93,7 +93,7 @@ in
## deep patch
```n
```dcdl
Base = {
feature_hoge = {
enable = Bool default true;
@ -108,7 +108,7 @@ Patched = Base // {
`Patched` は以下に相当する。
```n
```dcdl
{
feature_hoge = {
enable = false;
@ -119,7 +119,7 @@ Patched = Base // {
## 循環 import
```n
```dcdl
# main.n
{
schema = {
@ -130,7 +130,7 @@ Patched = Base // {
}
```
```n
```dcdl
# func.n
(input: (import ./main.n).schema) =>
{

View File

@ -2,7 +2,7 @@
array expression は、順序付きの値の列を表す。
```n
```dcdl
[1, 2, 3]
["a", "b", "c"]
```

View File

@ -6,7 +6,7 @@ composition expression は、複数の値・制約・構造を合成する式で
`&` は制約を保った合成を行う。
```n
```dcdl
Port = Int & >= 1 & <= 65535;
Config = MyConfig & { port = 8000; };
```
@ -15,7 +15,7 @@ Config = MyConfig & { port = 8000; };
`//` は右辺優先の構造的 patch を行う。
```n
```dcdl
Patched = Base // {
feature_hoge.enable = false;
};

View File

@ -2,7 +2,7 @@
`default` expression は、明示値が存在しない場合に materialize 時に採用される fallback を指定する。
```n
```dcdl
port = Int default 8080;
```

View File

@ -2,7 +2,7 @@
function call expression は、関数値を引数に適用する式である。
```n
```dcdl
mk_hw({
greet = "Hello";
target = "World";

View File

@ -2,7 +2,7 @@
function expression は、引数を受け取り式を返す値である。
```n
```dcdl
(part: {
greet = String;
target = String;

View File

@ -2,7 +2,7 @@
identifier expression は、現在の環境に束縛された名前を参照する式である。
```n
```dcdl
Port
MyConfig
mkConfig

View File

@ -2,7 +2,7 @@
import expression は、外部ファイルを読み込み、そのファイルの評価結果を返す。
```n
```dcdl
import ./config.n
import "./config.n"
```

View File

@ -2,7 +2,7 @@
let expression は、ローカル束縛を作る。
```n
```dcdl
let
part = {
greet = "Hello";

View File

@ -4,7 +4,7 @@ literal expression は、ソース上に直接書かれる具体値である。
## 種類
```n
```dcdl
"hello"
123
3.14

View File

@ -2,7 +2,7 @@
match expression は、対象値を上から順に pattern と照合し、最初に一致した分岐を採用する。
```n
```dcdl
foo = match inputs.a.hoge {
>= 20: {
value = 200;

View File

@ -2,7 +2,7 @@
object expression は、名前付き field の集合を表す。
```n
```dcdl
{
host = "127.0.0.1";
port = 8000;
@ -11,7 +11,7 @@ object expression は、名前付き field の集合を表す。
object は設定値にもスキーマにも使う。
```n
```dcdl
MyConfig = {
host = String;
port = Int default 8080;
@ -22,7 +22,7 @@ MyConfig = {
ネストした field はドットパスでも定義できる。
```n
```dcdl
{
feature_hoge.enable = false;
}
@ -30,7 +30,7 @@ MyConfig = {
これは以下と同じ構造を表す。
```n
```dcdl
{
feature_hoge = {
enable = false;

View File

@ -2,7 +2,7 @@
path reference expression は、object のフィールドを参照する式である。
```n
```dcdl
config.host
config.feature_hoge.enable
```

View File

@ -2,7 +2,7 @@
string interpolation は、文字列内に式を埋め込む候補機能である。
```n
```dcdl
"${part.greet}! ${part.target}"
```

View File

@ -4,7 +4,7 @@
## 構文
```n
```dcdl
(part: {
greet = String;
target = String;
@ -14,7 +14,7 @@
関数呼び出しは通常の呼び出し構文で行う。
```n
```dcdl
mk_hw({
greet = "Hello";
target = "World";
@ -23,7 +23,7 @@ mk_hw({
複数引数の構文は候補として以下を想定する。
```n
```dcdl
(
input_a: {
hoge = Int & >= 0;

View File

@ -1,6 +1,6 @@
# 言語仕様
このディレクトリは、遅延評価データ記述言語の仕様本文を章ごとに分割して管理する。
このディレクトリは、Decodal / DCDL の仕様本文を章ごとに分割して管理する。
目次はマニュアル直下の [Manual Index](../index.md) に集約する。
このファイルは `Language Specification` 章の入口としてだけ使う。

View File

@ -8,14 +8,14 @@
materialize は以下を行う。
- 必要なフィールドを評価する。
- 明示値がないフィールドに default を適用する。
- 明示値がない abstract value に default を適用する。
- 採用された値が制約を満たすか検証する。
- 未解決の制約だけが残っているフィールドをエラーにする。
- default を持たない未解決の abstract value をエラーにする。
- 未適用の関数など、データとして出力できない値をエラーにする。
## 例
```n
```dcdl
MyConfig = {
host = String;
port = Int default 8080;
@ -25,7 +25,7 @@ MyConfig = {
`MyConfig` を materialize すると、`host` は具体値も default もないためエラーになる。
`port``8080` が採用される。
```n
```dcdl
Config = MyConfig & {
host = "localhost";
};
@ -33,7 +33,7 @@ Config = MyConfig & {
`Config` を materialize すると以下になる。
```n
```dcdl
{
host = "localhost";
port = 8080;
@ -45,22 +45,22 @@ Config = MyConfig & {
`default` は materialize 時にのみ fallback として採用される。
```text
constraint = Int
value = none
default = 8080
Abstract {
constraints: [Int]
default: 8080
}
```
この cell を materialize すると、`8080` が採用され、`Int` を満たすか検証される。
この abstract value を materialize すると、`8080` が採用され、`Int` を満たすか検証される。
明示値がある場合、default は採用しない。
明示値は concrete value として表現され、default を保持しない。
```text
constraint = Int
value = 9000
default = 8080
Concrete(Int(9000))
```
この cell の最終値は `9000` である。
このの最終値は `9000` である。
## エラー分類
@ -81,7 +81,7 @@ default = 8080
`match` に fallback 分岐がなく、どの分岐にも一致しなかった場合はエラーになる。
```n
```dcdl
match value {
>= 10: "large";
}
@ -89,14 +89,10 @@ match value {
`value``10` 未満であれば失敗する。
## try / catch
## エラーは値ではない
`try / catch` は将来的な候補である
組み込み向けの小さな核では必須ではない。
エラーは runtime value ではなく diagnostic として扱う
通常の式はエラー内容に基づいて分岐できない。
失敗は主に以下から発生する。
- assert 相当の制約検証。
- `&` による合成。
- import。
- materialize。
汎用 `try / catch` は core には含めない。
fallback は `default`、`match`、および将来的な optional import / optional field access のような限定された仕組みで表現する。

View File

@ -4,7 +4,7 @@
## 構文
```n
```dcdl
import ./config.n
import "./config.n"
```
@ -24,7 +24,7 @@ import 先はモジュール単位で読み込まれる。
例:
```n
```dcdl
# main.n
{
schema = {
@ -35,7 +35,7 @@ import 先はモジュール単位で読み込まれる。
}
```
```n
```dcdl
# func.n
(input: (import ./main.n).schema) =>
{

View File

@ -12,7 +12,7 @@
例:
```n
```dcdl
IPv4Address
MyConfig
new_config

View File

@ -6,7 +6,7 @@
`&` は値・制約・構造を合成する演算子である。
```n
```dcdl
A & B
```
@ -22,7 +22,7 @@ A & B
例:
```n
```dcdl
Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;
@ -45,7 +45,7 @@ NarrowedPort & 8000
一方、以下は失敗する。
```n
```dcdl
BadConfig = MyConfig & {
port = 80;
};
@ -58,7 +58,7 @@ BadConfig = MyConfig & {
`//` は右辺優先の構造的 patch 演算子である。
`&` が制約を保った合成であるのに対し、`//` は設定やスキーマを上書き・変更するために使う。
```n
```dcdl
A // B
```
@ -74,7 +74,7 @@ A // B
つまり `//` は shallow merge ではなく deep patch とする。
```n
```dcdl
Base = {
feature_hoge = {
enable = Bool default true;
@ -91,7 +91,7 @@ Patched = Base // {
`Patched` は以下に相当する。
```n
```dcdl
{
feature_hoge = {
enable = false;
@ -102,7 +102,7 @@ Patched = Base // {
ドットパスを使うと以下のようにも書ける。
```n
```dcdl
Patched = Base // {
feature_hoge.enable = false;
};
@ -114,7 +114,7 @@ Patched = Base // {
候補として、`replace(...)` を組み込み関数として提供する。
```n
```dcdl
Replaced = Base // {
feature_hoge = replace({
enable = false;
@ -128,7 +128,7 @@ Replaced = Base // {
`&` は制約を満たす具体化に使う。
```n
```dcdl
ValidConfig = MyConfig & {
port = 8000;
};
@ -136,7 +136,7 @@ ValidConfig = MyConfig & {
`//` は既存構造の上書きや変形に使う。
```n
```dcdl
ModifiedSchema = MyConfig // {
port = Int default 9000;
};

View File

@ -3,11 +3,23 @@
この章では、表層構文の方針をまとめる。
厳密な EBNF は未確定であり、今後このファイルに詳細化する。
## 言語名と拡張子
プロジェクト名は **Decodal** とする。
正式な説明名は **Deferred Constraint Data Language**、略称は **DCDL** とする。
ファイル拡張子は `.dcdl` とする。
```text
config.dcdl
schema.dcdl
service.dcdl
```
## コメント
コメントは `#` から行末までとする。
```n
```dcdl
# comment
host = "127.0.0.1"; # trailing comment
```
@ -17,7 +29,7 @@ host = "127.0.0.1"; # trailing comment
オブジェクトフィールド、let 束縛、match 分岐はセミコロンで区切る。
末尾セミコロンは許可する。
```n
```dcdl
{
host = "127.0.0.1";
port = 8000;
@ -29,7 +41,7 @@ host = "127.0.0.1"; # trailing comment
識別子の厳密な字句規則は未確定である。
慣習としては `lower_snake`、`lowerCamel`、`UpperCamel` を使える想定とする。
```n
```dcdl
my_config
mkConfig
IPv4Address
@ -39,14 +51,14 @@ IPv4Address
ドットによるフィールド参照を許可する。
```n
```dcdl
config.host
config.feature_hoge.enable
```
オブジェクト内では、ドットパスによるフィールド定義も許可する。
```n
```dcdl
{
feature_hoge.enable = false;
}
@ -54,7 +66,7 @@ config.feature_hoge.enable
これは以下と同じ構造を表す。
```n
```dcdl
{
feature_hoge = {
enable = false;

View File

@ -4,7 +4,7 @@
## 例
```n
```dcdl
enable = Bool default true;
disable = Bool default false;
```
@ -13,7 +13,7 @@ disable = Bool default false;
`Bool` が受け入れるリテラルは以下である。
```n
```dcdl
true
false
```

View File

@ -4,7 +4,7 @@
## 例
```n
```dcdl
ratio = Float;
threshold = Float default 0.5;
```

View File

@ -4,7 +4,7 @@
primitive type は、通常のデータ値ではなく、値が満たすべき組み込み制約として扱う。
```n
```dcdl
name = String;
retry = Int default 3;
ratio = Float;

View File

@ -4,7 +4,7 @@
## 例
```n
```dcdl
retry = Int default 3;
port = Int & >= 1 & <= 65535;
```
@ -13,6 +13,6 @@ port = Int & >= 1 & <= 65535;
数値比較制約と合成できる。
```n
```dcdl
NarrowedPort = Int & >= 1 & <= 65535 & > 443;
```

View File

@ -4,7 +4,7 @@
## 例
```n
```dcdl
name = String;
greeting = String default "hello";
```
@ -13,7 +13,7 @@ greeting = String default "hello";
`String` は文字列制約と合成できる。
```n
```dcdl
message = String & /Hello! .*/;
```

View File

@ -5,7 +5,6 @@
## 構文
- 正式なファイル拡張子。
- 正式な字句・構文仕様。
- 演算子の優先順位。
- `rec` の扱い。
@ -56,6 +55,7 @@
## エラー処理
- `try / catch` を言語核に入れるか。
- エラー値を通常値として扱えるようにするか。
- optional import を導入するか。
- optional field access を導入するか。
- optional fallback が捕捉できる失敗の範囲。
- エラー報告に制約由来の説明をどこまで含めるか。