Trim open issues to materialization
This commit is contained in:
parent
8e1cb01f52
commit
6d80c66144
|
|
@ -59,8 +59,9 @@ Config = MyConfig & {
|
|||
|
||||
## default の合成
|
||||
|
||||
初期方針では、`&` による異なる default 同士の合成は conflict とする。
|
||||
同じ default は同一候補として扱ってよい。
|
||||
`&` で片方だけが default を持つ場合、その default を保持する。
|
||||
同じ thunk 由来の default 同士は同一 default として保持する。
|
||||
異なる default 同士は conflict とする。
|
||||
|
||||
```text
|
||||
merge_default(None, None) -> None
|
||||
|
|
|
|||
|
|
@ -84,5 +84,5 @@ module root や field は thunk として保持され、参照されたときだ
|
|||
関数引数は thunk として関数の environment に束縛する。
|
||||
関数本体で引数が参照されたときだけ force する。
|
||||
|
||||
任意の関数呼び出し結果をグローバルに memoize する必要はない。
|
||||
関数呼び出し結果そのものはグローバルには memoize しない。
|
||||
field に束縛された関数呼び出し結果は、その field thunk の評価結果として memoize される。
|
||||
|
|
|
|||
|
|
@ -188,11 +188,12 @@ RuntimeValue =
|
|||
|
||||
## default の合成
|
||||
|
||||
同じフィールドに複数の `default` が合成された場合の詳細規則は未確定である。
|
||||
現時点の単純な方針は以下である。
|
||||
`default` の合成規則は以下である。
|
||||
|
||||
- `&` による default 同士の衝突はエラーにする。
|
||||
- 同一 default 値は許可してよい。
|
||||
- `//` による patch では右辺 default が左辺 default を置き換える。
|
||||
- `&` で片方だけが default を持つ場合、その default を保持する。
|
||||
- `&` で両方が異なる default を持つ場合、conflict になる。
|
||||
- `Abstract & Concrete` が成功した場合、結果は concrete value になり default は消える。
|
||||
- `//` では右辺が左辺を置き換える。object/object の場合は field ごとに再帰 patch されるため、右辺 field の default が左辺 field の default を置き換える。
|
||||
|
||||
この方針により、`&` は制約を保った合成、`//` は上書き操作として説明できる。
|
||||
`default` thunk は materialize 時に必要になった時点で評価する。
|
||||
評価された default value は、同じ abstract value に残っている制約を満たす必要がある。
|
||||
|
|
|
|||
|
|
@ -74,5 +74,5 @@ Error 評価失敗
|
|||
関数引数は thunk として渡せる。
|
||||
関数本体内で引数が参照されたときに評価する。
|
||||
|
||||
任意の関数呼び出し結果をグローバルに memoize することは必須ではない。
|
||||
関数呼び出し結果そのものはグローバルには memoize しない。
|
||||
ただし、フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
|
||||
|
|
|
|||
|
|
@ -5,21 +5,19 @@
|
|||
## 基本的な設定スキーマ
|
||||
|
||||
```dcdl
|
||||
rec {
|
||||
Host = IPv4Address;
|
||||
Host = IPv4Address;
|
||||
|
||||
Port = Int & >= 1 & <= 65535;
|
||||
NarrowedPort = Port & > 443;
|
||||
Port = Int & >= 1 & <= 65535;
|
||||
NarrowedPort = Port & > 443;
|
||||
|
||||
MyConfig = {
|
||||
host = Host;
|
||||
port = NarrowedPort default 8080;
|
||||
feature_hoge = {
|
||||
enable = Bool default true;
|
||||
fuga = Int default 10;
|
||||
};
|
||||
MyConfig = {
|
||||
host = Host;
|
||||
port = NarrowedPort default 8080;
|
||||
feature_hoge = {
|
||||
enable = Bool default true;
|
||||
fuga = Int default 10;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
NewConfig = MyConfig & {
|
||||
host = "127.0.0.1";
|
||||
|
|
@ -33,28 +31,20 @@ disabled_config = NewConfig & {
|
|||
enabled_config = NewConfig;
|
||||
```
|
||||
|
||||
## 関数と文字列生成
|
||||
## 関数と制約
|
||||
|
||||
```dcdl
|
||||
let
|
||||
maybe_hw = String & /Hello! .*/;
|
||||
part = {
|
||||
greet = String;
|
||||
target = String;
|
||||
};
|
||||
mk_hw = (part: part) =>
|
||||
maybe_hw & "${part.greet}! ${part.target}";
|
||||
Port = Int & >= 1 & <= 65535;
|
||||
add_offset = (base: Port, offset: Int) => base + offset;
|
||||
in
|
||||
mk_hw({
|
||||
greet = "Hello";
|
||||
target = "World";
|
||||
})
|
||||
add_offset(8000, 80)
|
||||
```
|
||||
|
||||
評価結果:
|
||||
|
||||
```text
|
||||
"Hello! World"
|
||||
8080
|
||||
```
|
||||
|
||||
## match
|
||||
|
|
|
|||
|
|
@ -3,10 +3,7 @@
|
|||
function call expression は、関数値を引数に適用する式である。
|
||||
|
||||
```dcdl
|
||||
mk_hw({
|
||||
greet = "Hello";
|
||||
target = "World";
|
||||
})
|
||||
increment(41)
|
||||
```
|
||||
|
||||
## 評価
|
||||
|
|
@ -14,4 +11,5 @@ mk_hw({
|
|||
引数は thunk として渡せる。
|
||||
関数本体内で引数が参照されたときに評価する。
|
||||
|
||||
任意の関数呼び出し結果をグローバルに memoize することは必須ではない。
|
||||
関数呼び出し結果そのものはグローバルには memoize しない。
|
||||
フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@
|
|||
function expression は、引数を受け取り式を返す値である。
|
||||
|
||||
```dcdl
|
||||
(part: {
|
||||
greet = String;
|
||||
target = String;
|
||||
}) =>
|
||||
"${part.greet}! ${part.target}"
|
||||
(value: Int) => value + 1
|
||||
```
|
||||
|
||||
関数仕様の詳細は [関数](../functions.md) に置く。
|
||||
|
|
|
|||
|
|
@ -4,12 +4,10 @@ let expression は、ローカル束縛を作る。
|
|||
|
||||
```dcdl
|
||||
let
|
||||
part = {
|
||||
greet = "Hello";
|
||||
target = "World";
|
||||
};
|
||||
base = 8000;
|
||||
offset = 80;
|
||||
in
|
||||
"${part.greet}! ${part.target}"
|
||||
base + offset
|
||||
```
|
||||
|
||||
## 評価
|
||||
|
|
|
|||
|
|
@ -12,4 +12,5 @@ config.feature_hoge.enable
|
|||
左側の式を object として評価し、指定された field を参照する。
|
||||
参照先 field は必要になるまで評価されない。
|
||||
|
||||
存在しない field への参照をエラーにするか、open schema として扱うかは未確定である。
|
||||
存在しない field への参照は diagnostic になる。
|
||||
Decodal は unknown / Any のような値を伝播せず、field の有無を曖昧にしない。
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
# String Interpolation Expression
|
||||
# String Interpolation
|
||||
|
||||
string interpolation は、文字列内に式を埋め込む候補機能である。
|
||||
文字列補間は初期実装には含めない。
|
||||
|
||||
```dcdl
|
||||
"${part.greet}! ${part.target}"
|
||||
```
|
||||
Decodal の string literal は、現時点では literal text として扱う。
|
||||
式を埋め込む構文は定義しない。
|
||||
|
||||
## 評価
|
||||
|
||||
補間式の評価タイミングは通常の遅延評価に従う。
|
||||
文字列補間を初期実装に含めるかは未確定である。
|
||||
必要になった場合は、文字列連結や明示的な formatting function として別途設計する。
|
||||
|
|
|
|||
|
|
@ -5,54 +5,47 @@
|
|||
## 構文
|
||||
|
||||
```dcdl
|
||||
(part: {
|
||||
greet = String;
|
||||
target = String;
|
||||
}) =>
|
||||
"${part.greet}! ${part.target}"
|
||||
(value: Int) => value + 1
|
||||
```
|
||||
|
||||
関数呼び出しは通常の呼び出し構文で行う。
|
||||
|
||||
```dcdl
|
||||
mk_hw({
|
||||
greet = "Hello";
|
||||
target = "World";
|
||||
})
|
||||
let
|
||||
increment = (value: Int) => value + 1;
|
||||
in
|
||||
increment(41)
|
||||
```
|
||||
|
||||
複数引数の構文は候補として以下を想定する。
|
||||
複数引数も指定できる。
|
||||
|
||||
```dcdl
|
||||
(
|
||||
input_a: {
|
||||
hoge = Int & >= 0;
|
||||
},
|
||||
input_b: {
|
||||
fuga = 20;
|
||||
}
|
||||
) =>
|
||||
(input_a: { hoge = Int & >= 0; }, input_b: { fuga = Int; }) =>
|
||||
{
|
||||
# ...
|
||||
hoge = input_a.hoge;
|
||||
fuga = input_b.fuga;
|
||||
}
|
||||
```
|
||||
|
||||
## 関数の意味
|
||||
|
||||
関数は値として扱える。
|
||||
ただし、最終データとして関数値を出力できるかどうかは別途定める。
|
||||
設定ファイルを materialize する段階では、未適用の関数値は出力不能な値として扱うのが自然である。
|
||||
関数は runtime value として扱えるが、最終データとして materialize することはできない。
|
||||
未適用の関数値が materialize 対象に残っている場合は diagnostic になる。
|
||||
|
||||
関数値は opaque であり、関数値同士の等価性は提供しない。
|
||||
`&` で関数値同士を合成すると conflict になる。
|
||||
|
||||
## 評価方針
|
||||
|
||||
関数は以下の方針を基本とする。
|
||||
関数は以下の方針で評価する。
|
||||
|
||||
- 関数は純粋である。
|
||||
- 関数はレキシカルスコープを持つ。
|
||||
- 関数は定義時の環境を参照として保持する。
|
||||
- 引数は必要になるまで評価しない。
|
||||
- フィールドに束縛された関数呼び出し結果は、そのフィールド評価結果として memoize される。
|
||||
- 任意の関数呼び出しそのものをグローバルに memoize することは必須ではない。
|
||||
- 引数は thunk として渡され、必要になるまで評価されない。
|
||||
- 関数呼び出し結果そのものはグローバルには memoize しない。
|
||||
- フィールドに束縛された関数呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
|
||||
- 再帰的な依存は thunk cycle として diagnostic になる。
|
||||
|
||||
関数値の内部モデル例:
|
||||
|
||||
|
|
@ -63,29 +56,3 @@ Function {
|
|||
env: EnvRef
|
||||
}
|
||||
```
|
||||
|
||||
## 関数と重さ
|
||||
|
||||
関数の文法・パーサー自体は大きくない。
|
||||
実装上の重さは、主に評価モデルと意味論から発生する。
|
||||
|
||||
注意点:
|
||||
|
||||
- クロージャが環境を掴む。
|
||||
- 引数を lazy にするか strict にするかを決める必要がある。
|
||||
- 関数呼び出し結果をどこまで memoize するかを決める必要がある。
|
||||
- 再帰関数を許可するかを決める必要がある。
|
||||
- 関数値同士の `&` をどう扱うかを決める必要がある。
|
||||
- 関数値を object に入れたとき、materialize 可能かを決める必要がある。
|
||||
- import 循環と関数適用が絡んだときの cycle detection が必要になる。
|
||||
|
||||
軽量に保つため、初期仕様では以下の制限を検討できる。
|
||||
|
||||
- 関数は pure。
|
||||
- lexical closure は許可。
|
||||
- 引数は thunk として渡す。
|
||||
- 関数本体は必要になるまで評価しない。
|
||||
- 関数値は opaque。
|
||||
- 関数同士の `&` は、同一関数参照以外は conflict。
|
||||
- 関数値は最終データとして出力できない。
|
||||
- 再帰は cycle error として扱う、または v1 では禁止する。
|
||||
|
|
|
|||
|
|
@ -95,4 +95,5 @@ match value {
|
|||
通常の式はエラー内容に基づいて分岐できない。
|
||||
|
||||
汎用 `try / catch` は core には含めない。
|
||||
fallback は `default`、`match`、および将来的な optional import / optional field access のような限定された仕組みで表現する。
|
||||
fallback は `default` と `match` で表現する。
|
||||
optional import や optional field access は core には含めない。
|
||||
|
|
|
|||
|
|
@ -29,7 +29,8 @@ result = schema;
|
|||
```
|
||||
|
||||
この場合、`result` の右辺の `schema` は同じ module の top-level field `schema` を参照する。
|
||||
通常の object literal 内の field を暗黙に recursive scope にするかは別仕様とする。
|
||||
通常の object literal 内の field は、その object 内の sibling field を暗黙には識別子として参照できない。
|
||||
object 内の値を参照する場合は、外側で束縛された値や明示的な path reference を使う。
|
||||
|
||||
## SourceLoader
|
||||
|
||||
|
|
|
|||
|
|
@ -183,19 +183,10 @@ Patched = Base // {
|
|||
|
||||
## object 全体の置換
|
||||
|
||||
`//` が deep patch である場合、object 全体を置き換えたいときの escape hatch が必要になる。
|
||||
`//` では object/object は常に deep patch される。
|
||||
object field 全体を特別に置き換えるための `replace(...)` 構文や組み込み関数は core には含めない。
|
||||
|
||||
候補として、`replace(...)` を組み込み関数として提供する。
|
||||
|
||||
```dcdl
|
||||
Replaced = Base // {
|
||||
feature_hoge = replace({
|
||||
enable = false;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
この場合、`feature_hoge` は再帰 patch されず、右辺の object に丸ごと置き換わる。
|
||||
object 全体を別構造にしたい場合は、patch 対象より外側で値を作り直す。
|
||||
|
||||
## `&` と `//` の使い分け
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# 構文と字句
|
||||
|
||||
この章では、表層構文の方針をまとめる。
|
||||
厳密な EBNF は未確定であり、今後このファイルに詳細化する。
|
||||
厳密な構文は [Grammar](./grammar.md) の EBNF を参照する。
|
||||
|
||||
## 言語名と拡張子
|
||||
|
||||
|
|
@ -93,9 +93,9 @@ config.feature_hoge.enable
|
|||
}
|
||||
```
|
||||
|
||||
## 予約語候補
|
||||
## 予約語
|
||||
|
||||
以下は予約語または予約構文として扱う候補である。
|
||||
以下は予約語として扱う。
|
||||
|
||||
```text
|
||||
let
|
||||
|
|
@ -105,11 +105,8 @@ import
|
|||
default
|
||||
true
|
||||
false
|
||||
rec
|
||||
```
|
||||
|
||||
`rec` の扱いは未確定である。
|
||||
|
||||
## 演算子
|
||||
|
||||
主要な演算子は以下である。
|
||||
|
|
|
|||
|
|
@ -9,7 +9,10 @@ ratio = Float;
|
|||
threshold = Float default 0.5;
|
||||
```
|
||||
|
||||
## 未確定事項
|
||||
## Int との関係
|
||||
|
||||
`Int` と `Float` の暗黙変換を許可するかは未確定である。
|
||||
軽量実装では、両者を明確に分ける方が単純である。
|
||||
`Int` と `Float` は primitive type constraint としては別の型である。
|
||||
`Float` constraint は concrete `Float` を要求し、`Int` constraint は concrete `Int` を要求する。
|
||||
|
||||
数値演算や比較式では `Int` と `Float` を同じ numeric value として扱える。
|
||||
混在した四則演算の結果は `Float` になる。
|
||||
|
|
|
|||
|
|
@ -17,4 +17,5 @@ greeting = String default "hello";
|
|||
message = String & /Hello! .*/;
|
||||
```
|
||||
|
||||
正規表現制約を必須機能にするかは未確定である。
|
||||
正規表現制約の検証は Rust crate の `regex` feature で有効化される。
|
||||
feature が無効な場合、正規表現制約は具体 string に対して検証できず diagnostic になる。
|
||||
|
|
|
|||
|
|
@ -1,60 +1,23 @@
|
|||
# 未確定事項
|
||||
|
||||
今後決める必要がある事項を管理する。
|
||||
詳細化するときは、各項目を該当する仕様ファイルへ移動または反映する。
|
||||
実装または仕様方針が固まった項目は、該当する仕様ファイルへ反映してここから外す。
|
||||
|
||||
## 構文
|
||||
## Materialize target and host projection
|
||||
|
||||
- 正式な字句・構文仕様。
|
||||
- 演算子の優先順位。
|
||||
- `rec` の扱い。
|
||||
- コメント構文を `#` のみにするか。
|
||||
Decodal の評価結果は、制約・default・関数値を含む中間値になり得る。
|
||||
そのため、Decodal 単独で常に「最終成果物」を一意に決めるのではなく、host 側が期待する型や出力形式を与えて materialize / decode する経路を明確にする必要がある。
|
||||
|
||||
## 型・制約
|
||||
決めること:
|
||||
|
||||
- 配列要素の制約表現。
|
||||
- object の open/closed schema の扱い。
|
||||
- 正規表現を必須機能にするか optional feature にするか。
|
||||
- 代表的な組み込み述語の範囲。
|
||||
- Rust API で評価結果の field/path を選択して decode / materialize できるようにするか。
|
||||
- `decodal-derive` の struct schema と評価結果を合成して decode する経路を、主要な materialize path として位置づけるか。
|
||||
- CLI / WASM では target path を指定して JSON-compatible value へ materialize する形にするか。
|
||||
- 制約や関数値が残った値を出力したい場合、materialize ではなく inspect/debug API として分けるか。
|
||||
|
||||
## default
|
||||
現時点の案:
|
||||
|
||||
- `default` 同士の conflict 解決規則。
|
||||
- `&` による default 合成の厳密な規則。
|
||||
- `//` による default 置換の厳密な規則。
|
||||
- default thunk の評価失敗をどの段階で報告するか。
|
||||
|
||||
## 演算子
|
||||
|
||||
- `//` による制約・default の置換詳細。
|
||||
- `replace(...)` を採用するか、別構文を設けるか。
|
||||
- 配列に対する patch 操作を右辺置換だけにするか。
|
||||
- 配列 append / prepend / remove などを提供するか。
|
||||
|
||||
## 関数
|
||||
|
||||
- 関数値の最終出力可否。
|
||||
- 再帰関数を許可するか。
|
||||
- 関数同士の `&` の扱い。
|
||||
- 関数値の等価性。
|
||||
- 関数呼び出し結果の memoize 範囲。
|
||||
|
||||
## 評価
|
||||
|
||||
- thunk のエラー memoize 方針。
|
||||
- import cache の単位。
|
||||
- 循環 import の診断メッセージ。
|
||||
- materialize 対象の範囲指定方法。
|
||||
|
||||
## match
|
||||
|
||||
- match の網羅性チェックを行うか。
|
||||
- 到達不能分岐を警告するか。
|
||||
- パターン構文の範囲。
|
||||
|
||||
## エラー処理
|
||||
|
||||
- optional import を導入するか。
|
||||
- optional field access を導入するか。
|
||||
- optional fallback が捕捉できる失敗の範囲。
|
||||
- エラー報告に制約由来の説明をどこまで含めるか。
|
||||
- Rust では `evaluate -> select field/path -> expected schema と合成 -> decode` を主経路にする。
|
||||
- CLI / WASM では、明示された target path または module 全体を JSON-compatible value として materialize する。
|
||||
- materialize できない unresolved abstract value、default のない制約値、関数値は diagnostic にする。
|
||||
- Decodal 言語内には materialize 構文を追加せず、host API / CLI / WASM の責務として扱う。
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user