Add associative map constraints and range refinement
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Composition and Materialization
|
||||
|
||||
`&`、`//`、`default`、materialize は、runtime value の variant に基づいて処理する。
|
||||
`&`、`//`、`as`、`default`、materialize は、runtime value の variant に基づいて処理する。
|
||||
|
||||
## `&`
|
||||
|
||||
@@ -89,7 +89,24 @@ patch(a: RuntimeValue, b: RuntimeValue) -> RuntimeValue
|
||||
- 配列、scalar、function は右辺置換とする。
|
||||
|
||||
`//` は制約を保持するための演算子ではない。
|
||||
制約を満たす具体化には `&` を使う。
|
||||
対称な制約合成には `&` を使い、左辺が右辺より狭いことを確認しながら合成する場合は `as` を使う。
|
||||
|
||||
## `as`
|
||||
|
||||
`as` は narrower と wider の向きを固定した範囲包含確認と合成である。
|
||||
|
||||
```text
|
||||
apply_as(narrower: RuntimeValue, wider: RuntimeValue)
|
||||
-> RuntimeValue | Diagnostic
|
||||
```
|
||||
|
||||
abstract / abstract では、左辺 constraints が右辺 constraints を包含することを確認し、左辺を結果にする。
|
||||
concrete / abstract では、concrete value が右辺 constraints を満たすことを確認する。
|
||||
|
||||
object / object では右辺を field domain とする。左辺にしかない field は診断し、両側にある field は再帰的に `apply_as` し、右辺にしかない field は thunk を force せずそのまま結果へ残す。
|
||||
この扱いは default の有無に依存しない。default は包含判定の根拠でも `as` の補完値でもなく、後の materialize だけが選択する。
|
||||
|
||||
`ArrayItems(wider)` は concrete array の全要素を、`MapValues(wider)` は concrete object の全 field value を同じ関数で絞り込む。
|
||||
|
||||
## materialize
|
||||
|
||||
|
||||
@@ -41,10 +41,10 @@ engine.bind_global(
|
||||
A user source can then refer to `Service` without importing it.
|
||||
|
||||
```dcdl
|
||||
Service & {
|
||||
{
|
||||
name = "api";
|
||||
port = 9443;
|
||||
}
|
||||
} as Service
|
||||
```
|
||||
|
||||
## HostValue
|
||||
@@ -60,6 +60,7 @@ HostValue =
|
||||
Bool
|
||||
Array(Vec<HostValue>)
|
||||
ArrayConstraint { item, constraints, default }
|
||||
MapConstraint { value, constraints, default }
|
||||
Object(Vec<HostField>)
|
||||
Abstract { constraints, default }
|
||||
```
|
||||
@@ -69,6 +70,9 @@ When a host value is bound, the engine internalizes it into `RuntimeValue` and a
|
||||
`HostValue::array_of(item)` builds an array constraint with a required element schema.
|
||||
There is no host API for an unconstrained abstract array.
|
||||
|
||||
`HostValue::map_of(value)` builds a map constraint whose arbitrary object field values must satisfy `value`.
|
||||
`BTreeMap<String, T>` and, with `std`, `HashMap<String, T>` implement `DecodalSchema`, `DecodalDecode`, and `IntoHostValue` using this representation.
|
||||
|
||||
## Abstract host objects
|
||||
|
||||
A host-provided schema object is represented as a concrete object structure whose fields may contain abstract values.
|
||||
|
||||
@@ -16,7 +16,8 @@ demand-driven evaluation
|
||||
├─ load imported module on demand
|
||||
├─ evaluate expression
|
||||
├─ compose `&`
|
||||
└─ patch `//`
|
||||
├─ patch `//`
|
||||
└─ validate `as`
|
||||
↓
|
||||
materialize
|
||||
↓
|
||||
@@ -105,9 +106,16 @@ eval(A // B):
|
||||
a = eval(A)
|
||||
b = eval(B)
|
||||
patch(a, b)
|
||||
|
||||
eval(A as S):
|
||||
narrower = eval(A)
|
||||
wider = eval(S)
|
||||
apply_as(narrower, wider)
|
||||
```
|
||||
|
||||
`&` は制約を保った合成を行い、`//` は右辺優先の deep patch を行う。
|
||||
`&` は制約を保った対称な合成を行い、`//` は右辺優先の deep patch を行う。
|
||||
`as` は左辺が右辺より狭いことを再帰的に確認する。左辺で絞られた部分は左辺を使い、右辺だけの部分は abstract のまま保持する。
|
||||
default は `as` では選択せず、materialize まで遅延する。
|
||||
詳細は [Composition and Materialization](./composition-and-materialization.md) に置く。
|
||||
|
||||
## resolver / binder
|
||||
@@ -140,7 +148,7 @@ resolver / binder を追加すると、以下を早期に診断しやすくな
|
||||
- import path の一部静的解決
|
||||
- span 付き diagnostic の精度向上
|
||||
|
||||
ただし、Decodal の制約検証は独立した type checking pass ではなく、`&` の合成時や materialize 時に行う。
|
||||
ただし、Decodal の制約検証は独立した type checking pass ではなく、`&` の合成時、`as` の適用時、materialize 時に行う。
|
||||
|
||||
## materialize
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ Core に入れる機能は、基本的に deterministic な value transformation
|
||||
- arithmetic / logical / comparison operators
|
||||
- array concat
|
||||
- object / constraint composition
|
||||
- asymmetric range refinement and homogeneous map constraints
|
||||
- default materialization
|
||||
- pure function evaluation
|
||||
- host supplied import evaluation
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
## 方針
|
||||
|
||||
初期処理系は AST interpreter として実装する。
|
||||
bytecode VM や JIT ではなく、AST を demand-driven に評価することで、遅延評価、循環参照、`default`、`&`、`//` の意味論を小さく実装する。
|
||||
bytecode VM や JIT ではなく、AST を demand-driven に評価することで、遅延評価、循環参照、`default`、`&`、`//`、`as` の意味論を小さく実装する。
|
||||
|
||||
## 構成
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ constraint は concrete value とは別の型として扱う。
|
||||
Constraint =
|
||||
Type(PrimitiveType)
|
||||
ArrayItems(ThunkId)
|
||||
MapValues(ThunkId)
|
||||
Compare(Op, Literal)
|
||||
Regex(Pattern)
|
||||
BuiltinPredicate(Symbol)
|
||||
@@ -133,6 +134,9 @@ Constraint =
|
||||
`ArrayItems` は配列そのものの型と、すべての要素へ合成する schema thunk を表す。
|
||||
配列用の primitive type は持たず、抽象配列には必ず要素制約が必要である。
|
||||
|
||||
`MapValues` は object の key 集合を制限せず、すべての field value へ適用する schema thunk を表す。
|
||||
連想配列は materialize 後も `Data::Object` になり、別の data variant は持たない。
|
||||
|
||||
初期実装では、object の形は主に `Concrete(Object)` の field に `Abstract` を置くことで表現する。
|
||||
object 全体にかかる constraint は必要になった時点で追加する。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user