Decodal
This commit is contained in:
@@ -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` が合成された場合の詳細規則は未確定である。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## 基本方針
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
{
|
||||
schema = {
|
||||
hoge = String;
|
||||
@@ -46,7 +46,7 @@ Error 評価失敗
|
||||
|
||||
## 循環検出
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
{
|
||||
a = b + 1;
|
||||
b = a + 1;
|
||||
|
||||
@@ -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) =>
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
array expression は、順序付きの値の列を表す。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
[1, 2, 3]
|
||||
["a", "b", "c"]
|
||||
```
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
`default` expression は、明示値が存在しない場合に materialize 時に採用される fallback を指定する。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
port = Int default 8080;
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
function call expression は、関数値を引数に適用する式である。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
mk_hw({
|
||||
greet = "Hello";
|
||||
target = "World";
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
function expression は、引数を受け取り式を返す値である。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
(part: {
|
||||
greet = String;
|
||||
target = String;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
identifier expression は、現在の環境に束縛された名前を参照する式である。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
Port
|
||||
MyConfig
|
||||
mkConfig
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import expression は、外部ファイルを読み込み、そのファイルの評価結果を返す。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
import ./config.n
|
||||
import "./config.n"
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
let expression は、ローカル束縛を作る。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
let
|
||||
part = {
|
||||
greet = "Hello";
|
||||
|
||||
@@ -4,7 +4,7 @@ literal expression は、ソース上に直接書かれる具体値である。
|
||||
|
||||
## 種類
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
"hello"
|
||||
123
|
||||
3.14
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
match expression は、対象値を上から順に pattern と照合し、最初に一致した分岐を採用する。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
foo = match inputs.a.hoge {
|
||||
>= 20: {
|
||||
value = 200;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
path reference expression は、object のフィールドを参照する式である。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
config.host
|
||||
config.feature_hoge.enable
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
string interpolation は、文字列内に式を埋め込む候補機能である。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
"${part.greet}! ${part.target}"
|
||||
```
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 言語仕様
|
||||
|
||||
このディレクトリは、遅延評価データ記述言語の仕様本文を章ごとに分割して管理する。
|
||||
このディレクトリは、Decodal / DCDL の仕様本文を章ごとに分割して管理する。
|
||||
|
||||
目次はマニュアル直下の [Manual Index](../index.md) に集約する。
|
||||
このファイルは `Language Specification` 章の入口としてだけ使う。
|
||||
|
||||
@@ -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 のような限定された仕組みで表現する。
|
||||
|
||||
@@ -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) =>
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
例:
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
IPv4Address
|
||||
MyConfig
|
||||
new_config
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
## 例
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
ratio = Float;
|
||||
threshold = Float default 0.5;
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
primitive type は、通常のデータ値ではなく、値が満たすべき組み込み制約として扱う。
|
||||
|
||||
```n
|
||||
```dcdl
|
||||
name = String;
|
||||
retry = Int default 3;
|
||||
ratio = Float;
|
||||
|
||||
@@ -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;
|
||||
```
|
||||
|
||||
@@ -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! .*/;
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user