Skip to content

構文規範

本ファイルは YaoXiang プログラミング言語の構文規範を定義ものであり字句構造、構文規則、演算子優先順位を含みます。


第1章:字句構造

1.1 ソースファイル

YaoXiang ソースファイルは UTF-8 エンコーディングを使用する必要があります。ソースファイルは通常 .yx を拡張子とします。

1.2 字句トークン分類

カテゴリ説明
識別子文字またはアンダースコアで開始x, _private, my_var
キーワード言語定義の予約語Type, pub, use
リテラル固定値42, "hello", true
演算子演算記号+, -, *, /
区切り子構文区切り(, ), {, }, ,

1.3 キーワード

YaoXiang は極めて少数のキーワードを定義しています:

pub    use    spawn
ref    mut    if     else
else   match  while  for    return
break  continue as     in     unsafe

これらのキーワードは任意のコンテキストにおいて特殊意味を持ち、識別子として使用できません。

1.4 予約語

YaoXiang の「予約語」は3層構成であり、パーサー(parser)と型検査器(type checker)が異なる段階で識別します:

1.4.1 リテラルの予約語

パーサーが独立したトークンを持つリテラル識別子は通常の識別子として使用できません:

識別子所属型説明
Typeメタ型キーワード
trueBoolブール真値
falseBoolブール偽値
voidVoidVoid リテラル(Unit 値)。小文字 void は値リテラル、大文字 Void は型名(§1.4.3 参照)。

1.4.2 構築子式

以下の構築子はパターン照合および式のコンテキストでパーサーによって識別されます:

構築子所属型説明
some(T)OptionOption 値変体構築
ok(T)ResultResult 成功変体
err(E)ResultResult エラー変体

1.4.3 組み込み型名

以下の型名は型検査器によって事前登録されており、インポートなしで使用できます。パーサーはこれらを通常の識別子として扱います——予約語ではなく、局所束縛で shadow 可能(推奨はしません)

型名論理対応説明
Void⊤(真/Unit)零フィールド積型、ちょうど1つの常住者(void リテラル、§1.4.1 参照)
Never⊥(偽/空型)零バリアントを持つ型で常住者が存在しない。任何の式も Never 値を生成できません。Never <: T は全ての T に対して成立(爆発原理)。
Int符号付き整数
Float浮動小数点数
Boolブール値:true / false
CharUnicode 文字
String文字列

1.5 識別子

識別子は文字またはアンダースコアで開始し、後続の文字は文字、数字、またはアンダースコアを使用できます。識別子は大小文字を区別します。

特殊識別子:

  • _ はプレースホルダーとして使用され、特定の値を無視することを示します
  • アンダースコアで始まる識別子はプライベートメンバーを示します

1.6 リテラル

1.6.1 整数

Decimal     ::= [0-9][0-9_]*
Octal       ::= 0o[0-7][0-7_]*
Hex         ::= 0x[0-9a-fA-F][0-9a-fA-F_]*
Binary      ::= 0b[01][01_]*

1.6.2 浮動小数点数

Float       ::= [0-9][0-9_]* '.' [0-9][0-9_]* ([eE][+-]?[0-9][0-9_]*)?

1.6.3 文字列

String      ::= '"' ([^"\\] | EscapeSequence)* '"'
Escape      ::= '\\' ([nrt'"\\] | UnicodeEscape)
Unicode     ::= 'u' '{' HexDigit+ '}'

1.6.4 コレクション

List        ::= '[' Expr (',' Expr)* ']'
Dict        ::= '{' String ':' Expr (',' String ':' Expr)* '}'
Set         ::= '{' Expr (',' Expr)* '}'

1.6.5 リスト内包表記

ListComp    ::= '[' Expr 'for' Identifier 'in' Expr (',' Expr)* ('if' Expr)? ']'

1.6.6 メンバー検査

Membership  ::= Expr 'in' Expr

1.7 コメント

// 単一行コメント

/* 複数行コメント
   複数行にまたがる可能 */

1.8 インデント規則

コードは4スペースのインデントを使用する必要があります。Tab 文字の使用は禁止です。これは強制的な構文規則です。


第2章:構文規則

2.1 式分類

Expr        ::= Literal
              | Identifier
              | FnCall
              | MemberAccess
              | IndexAccess
              | UnaryOp
              | BinaryOp
              | TypeCast
              | RangeExpr
              | ErrorPropagate
              | RefExpr
              | IfExpr
              | MatchExpr
              | Block
              | Lambda

2.2 演算子優先順位

優先順位演算子結合性
1() [] . ?左から右
2as左から右
3* / %左から右
4+ -左から右
5..左から右
6<< >>左から右
7& | ^左から右
8== != < > <= >=左から右
9not右から左
10and or左から右
11if...else右から左
12= += -= *= /=右から左

2.3 関数呼び出し

FnCall      ::= Expr '(' ArgList? ')'
ArgList     ::= Expr (',' Expr)* (',' NamedArg)* | NamedArg (',' NamedArg)*
NamedArg    ::= Identifier ':' Expr

2.4 メンバーアクセス

MemberAccess::= Expr '.' Identifier

2.5 インデックスアクセス

IndexAccess ::= Expr '[' Expr ']'

2.6 型キャスト

TypeCast    ::= Expr 'as' TypeExpr

2.7 条件式

IfExpr      ::= 'if' Expr Block ('else' 'if' Expr Block)* ('else' Block)?

2.8 パターン照合

MatchExpr   ::= 'match' Expr '{' MatchArm+ '}'
MatchArm    ::= Pattern ('|' Pattern)* ('if' Expr)? '=>' Expr ','
Pattern     ::= Literal
              | Identifier
              | Wildcard
              | StructPattern
              | TuplePattern
              | EnumPattern
              | OrPattern

2.9 ブロック式

Block       ::= '{' Stmt* Expr? '}'

統一セマンティクス:全ての {} ブロックの return セマンティクスは一貫しています:

ブロック型return セマンティクスデフォルト返り値
通常 {}値を返すVoid
unsafe {}型定義を返すVoid
spawn {}結果を返すVoid

基本原則

  • {} 内の return は常に内容を上位スコープに返します
  • return がない場合のデフォルト返り値は Void
  • 式形式 = expr は直接値を返します
yaoxiang
// 通常 {} ブロック:return で値を返す
result = {
    x = compute()
    return x  // 上位スコープに値を返す
}

// unsafe {} ブロック:return で型定義を返す
SqliteDb = unsafe {
    SqliteDb: Type = {
        handle: *Void
    }
    return SqliteDb  // 型定義を上位スコープに返す
}

// spawn {} ブロック:return で結果を返す
(a, b) = spawn {
    result1 = fetch("url1"),
    result2 = fetch("url2")
    return (result1, result2)  // 結果を上位スコープに返す
}

2.10 ラムダ式

Lambda      ::= '(' ParamList? ')' '=>' Expr
            |  '(' ParamList? ')' '=>' Block

2.11 エラー伝播演算子

ErrorPropagate ::= Expr '?'

? 演算子は後置演算子であり、優先順位は . と同レベルです。Result(T, E) 型に対して:

  • Ok(v) の場合は値 v を抽出して続行
  • Err(e) の場合はエラーを上位に伝播(return Err(e)
yaoxiang
process: (data: Data) -> Result(Data, Error) = {
    validated = validate(data)?     // 成功時:値を抽出、失敗時:上位に伝播
    transform(validated)
}

2.12 範囲式

RangeExpr   ::= Expr '..' Expr

.. は範囲型を作成し、for ループとスライスに使用されます。

yaoxiang
for i in 0..10 { print(i) }
slice = array[0..5]

2.13 ref 式

RefExpr     ::= 'ref' Expr

ref は共有所有権を作成します。コンパイラが自動的に Rc(単一タスク)または Arc(タスク間)を選択するため、ユーザーは実装詳細を気にする必要はありません。

yaoxiang
data = ref heavy_data
spawn { use(data) }   // タスク間:コンパイラが自動的に Arc を選択

2.14 unsafe 式

UnsafeExpr  ::= 'unsafe' Block

unsafe ブロックは不透明型和裸ポインタ操作の定義に使用されます。return を使用して型定義を上位スコープに返します。

セマンティクス

  • unsafe {} 内で型和裸ポインタ操作を定義できます
  • 返された型は unsafe {} 外で使用可能
  • 型のフィールドアクセスには unsafe 権限が必要
yaoxiang
// unsafe ブロック内で不透明型を定義
SqliteDb = unsafe {
    SqliteDb: Type = {
        handle: *Void  // 裸ポインタ
    }
    return SqliteDb
}

// SqliteDb は unsafe ブロック外で使用可能
db = sqlite3_open("test.db")

2.15 スコープ

基本規則

  • {} ブロックはスコープを作成します
  • 内側スコープは外側スコープの変数にアクセス可能
  • 外側スコープは内側スコープの変数にアクセス不可
  • 変数宣言は「代入優先」原則に従います
yaoxiang
// ブロックスコープ
{
    x = 10
    // x はこのスコープ内で可視
}
// x はこのスコープ外で不可視

// 関数スコープ
add: (a: Int, b: Int) -> Int = {
    result = a + b
    return result
}
// result は関数外で不可視

変数宣言とシャドーイング

  • x = value:スコープチェーンを外に向かって検索し、x が見つかれば代入、なければ新規宣言
  • mut x = value:明示的な新規可変宣言。上位スコープの同名変数を禁止
  • 同一スコープ内で同じ名前は一度のみ宣言可能

詳細定義:スコープの完全な規則、変数宣言およびシャドーイング機構の詳細についてはモジュールシステム規範を参照してください。


第3章:文

3.1 文分類

Stmt        ::= LetStmt
              | ExprStmt
              | ReturnStmt
              | BreakStmt
              | ContinueStmt
              | IfStmt
              | MatchStmt
              | WhileStmt
              | ForStmt
              | SpawnStmt

3.2 変数宣言

LetStmt     ::= ('mut')? Identifier (':' TypeExpr)? '=' Expr

3.3 return 文

ReturnStmt  ::= 'return' Expr?

セマンティクスreturn はコードブロックから値を返すために使用されます。return がない場合、コードブロックはデフォルトで Void を返します。

3.4 break 文

BreakStmt   ::= 'break' Identifier?

3.5 continue 文

ContinueStmt::= 'continue'

3.6 if 文

IfStmt      ::= 'if' Expr Block ('else' 'if' Expr Block)* ('else' Block)?

3.7 match 文

MatchStmt   ::= 'match' Expr '{' MatchArm+ '}'

3.8 while 文

WhileStmt   ::= 'while' Expr Block

3.9 for 文

ForStmt     ::= 'for' 'mut'? Identifier 'in' Expr Block

3.9.1 セマンティクス:各イテレーションは新しい値を束縛

YaoXiang の for ループは従来の言語異なります:各イテレーションは新しい値を束縛であり、同じ変数を変更するものではありません

yaoxiang
// 例:for i in 1..5
for i in 1..5 {
    print(i)
}

実行プロセス

イテレーションループ変数の動作
1回目新規束縛 i = 1 を作成、ループ本体実行、1 を出力
2回目新規束縛 i = 2 を作成(以前の束縛は破棄済み)、ループ本体実行、2 を出力
3回目新規束縛 i = 3 を作成、ループ本体実行、3 を出力
4回目新規束縛 i = 4 を作成、ループ本体実行、4 を出力
終了ループ本体終了、束縛破棄

要点:各イテレーション終了後、そのイテレーションで作成された束縛は破棄されます。次のイテレーションは前回の束縛とは全く関係のない新規の束縛です。

3.9.2 for と for mut の違い

構文ループ変数の可変性説明
for i in 1..5不変ループ本体内で束縛を変更不可
for mut i in 1..5可変ループ本体内で束縛を変更可能
yaoxiang
// 有効:各イテレーションで新しい値を束縛するため、変更の必要なし
for i in 1..5 {
    print(i)  // i の値を読み取り
}

// 誤り:不変束縛なので変更不可
for i in 1..5 {
    i = i + 1  // 誤り:不変束縛は変更不可
}

// 有効:for mut を使用すると束縛の変更を許可
for mut i in 1..5 {
    i = i + 1  // 許可
}

3.9.3 シャドーイング検査

YaoXiang は変数のシャドーイングを禁止します。for ループ変数は上位スコープの変数と同じ名前を使用できません:

yaoxiang
// 誤り:i はすでに外部で宣言済み
i = 10
for i in 1..5 {
    print(i)
}

// 正しい:異なる変数名を使用
i = 10
for j in 1..5 {
    print(j)
}

この規則は全てのコードブロックに適用されます。詳細については4.3 シャドーイング規則を参照してください。

3.9.4 他の言語との比較

言語for ループ変数のセマンティクス
YaoXiang各イテレーションで新しい値を束縛
Rust同じ変数を変更(mut が必要)
Python同じ変数を変更(mut 不要)
C/C++同じ変数を変更(ポインタまたは参照が必要)

設計理由:YaoXiang が束縛セマンティクスを選択したのは:

  1. より自然なセマンティクスに符合 自然言語では「集合内の各要素 x について」は、各 x が独立した存在であることを意味します。YaoXiang の for i in 1..5 は「1 から 5 の中の各 i について」と読み、各イテレーションの i は全く新しい束縛であり、人間の直感と一致します。

  2. 偶発的な変更を回避 デフォルトで不変の束縛セマンティクスは、ループ本体内でループ変数を偶発的に変更できないことを意味します。複雑なループ本体内でうっかり i = ... と書いて追跡困難なバグを発生させる心配がありません。

  3. 高性能ソリューションが簡単に利用可能 イテレーション間で変数を再利用する必要がある場合(例:アキュムレータ、キャッシュ)、for mut を使用して可変束縛モードに切り替えられます。これは暗黙の共有状態より明確です——意図は構文で明示的に表現され、ランタイム動作に隠されません。

3.10 spawn 文

SpawnBlock  ::= '(' Pattern (',' Pattern)* ')' '=' 'spawn' '{' Expr (',' Expr)* '}'
SpawnFor    ::= Identifier '=' 'spawn' 'for' 'mut'? Identifier 'in' Expr '{' Expr '}'
SpawnStmt   ::= SpawnBlock | SpawnFor

spawn ブロック:並行領域を明示的に宣言し、ブロック内の式は並行実行されます。

yaoxiang
(result_a, result_b) = spawn {
    parse(fetch("url1")),
    parse(fetch("url2"))
}

spawn ループ:データ並列ループ。

yaoxiang
results = spawn for item in items {
    process(item)
}

付録:構文クイックリファレンス

A.1 制御フロー

if Expr Block (else if Expr Block)* (else Block)?
match Expr { MatchArm+ }
while Expr Block
for 'mut'? Identifier 'in' Expr Block

A.2 エラー処理

Expr '?'              // エラー伝播(Result 型)

A.3 match 構文

match value {
    pattern1 => expr1,
    pattern2 if guard => expr2,
    _ => default_expr,
}