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