構文リファレンス

NagiScript の構文全体を解説します。

現行仕様

このページは現行コンパイラーの正仕様に合わせてあります。実際に使えるキーワードは「fn, val, var, if, else, for, while, match, struct, enum, impl, unsafe, extern, export, return, in, as, break, continue, true, false, print, println, panic」と、for の増分指定 step です(2026-08 の変更履歴 change.md で追加)。それ以外のキーワード(import / loop / async / await / type / const / class / interface / trait / pub / and / or / not / null / void など)は未実装であり、現行の nagiscript コマンドではコンパイルできません。


プログラム構造

基本構造

main.ngs
// 出力は print / println(argc はちょうど 1 個)
fn main() {
    println("Hello, World!")
    println(42)
}
ロードマップ(未実装)

import は未実装です。複数ファイルへの分割はできません。また const(定数定義)や void の戻り値型も存在しません。戻り値のない関数は -> を書きません。出力は組み込みの print / println を使い、io.println や std:io は利用できません。


変数宣言

不変変数

main.ngs
val x: i32 = 42
val name = "NagiScript"  // 型推論

可変変数

main.ngs
var counter: i32 = 0
counter = 10  // OK
counter = counter + 1  // OK
補足

変数宣言は val(不変)と var(可変)の 2 種類です。定数キーワード const は存在しません。文字列の型名は string であり、str は unknown type str エラーになります。


関数定義

基本構文

main.ngs
fn add(a: i32, b: i32) -> i32 {
    return a + b
}
現行仕様(v0.2.0)

関数定義は fn name(...) -> 型 { ... } の形で、戻り値の型は -> 構文で指定します。-> を省略した場合やブロック末尾の暗黙 return(式ブロック)は非対応です。戻り値を返す関数では必ず return を明示してください。

ジェネリクス関数

main.ngs
fn first(list: List<i32>) -> i32 {
    return list[0]
}
ロードマップ(未実装)

関数式(無名関数)の安定利用は未対応です。また List<T> のジェネリクスは、LLVM コード生成で zext i64 to i64 エラーになりリンクに失敗する既知バグがあります。当面は構造体 + 値渡しを推奨します。


出力

main.ngs
fn main() {
    println("Hello, World!")  // 改行付き
    print("no newline")       // 改行なし
    print(42)
}
現行仕様(v0.2.0)

組み込みの出力は print(値) と println(値) です。引数はちょうど 1 個で、文字列・数値・bool を表示できます。文字列の + による連結は使えません("Hello" + " World" はコンパイルエラー)。


制御構文

if 文

main.ngs
if x > 5 {
    println("大きい")
} else {
    println("小さい")
}
補足(change.md, 2026-08)

関数のブロック末尾(} 直前)に置いた if / match は、返り値の tail 式として扱われます。if / else の両分岐が値を返せば、そのまま関数の戻り値になります (return 不要)。else が無い if x { return 1 } のような、戻り値の欠ける経路はコンパイルエラーになります。通常の文としての if も従来どおり使えますが、ブロック途中の値は変数への代入で保持してください。

while ループ

main.ngs
var i = 0
while i < 5 {
    println(i)
    i = i + 1
}

for ループ(step 対応)

main.ngs
for i in 0..10 step 2 { println(i) }   // 0 2 4 6 8
for i in 10..0 step -3 { println(i) }  // 10 7 4 1
for i in 0..5 { println(i) }           // 省略で 1 ずつ
現行仕様(change.md, 2026-08)

for の範囲ループに任意の増分(ステップ値)を指定する step 節が追加されました。省略時は従来どおり 1 ずつ増えます。負のステップは降順ループ (10..0 step -1)で使えます。継続条件は step * (end - i) > 0 で評価されるため、 0..10 step -1 のような「進まない向き」のループは即座に終了します。また、同じ変数名のループ変数を複数の for で使い回す再宣言バグも修正されています (while での書き換えも従来どおり可能)。

loop(未実装)

main.ngs
// loop は存在しない。while true を使う
while true {
    println("回る")
    break
}
ロードマップ(未実装)

無限ループ用の loop キーワードは存在しません。while true { ... } を使用してください。break / continue は使用できます。

match 式

main.ngs
enum Status { Ok NotFound }

fn show(s: Status) {
    val st = match s {
        Ok => "200",
        _ => "404",
    }
    println(st)
}
現行仕様(v0.2.0)

match のパターンは 裸の列挙バリアント名(Ok, NotFound など)と _ ワイルドカードを使用します。enum のバリアント値を生成するときは Status.Ok のように括弧は不要です(データを持つバリアントのみ括弧が必要、例: Some(42))。


型定義

構造体

main.ngs
struct Point { x: f32 y: f32 }
val p = Point { x: 3.0, y: 4.0 }
println(p.x)

impl ブロック(メソッド)

main.ngs
struct Point { x: f32 y: f32 }

impl Point {
    fn show(self: Point) -> string {
        return "point"
    }
}

fn main() {
    val p = Point { x: 1.0, y: 2.0 }
    println(p.show())
}
現行仕様(v0.2.0)

メソッドは impl ブロックに定義します。fn Point.distance_to(self: Point, ...) 形式は動きません。また self には型注釈が必須です。

ロードマップ(設計方針)

self の渡し方は将来的に「常に暗黙の参照渡し」(Python のオブジェクトモデルに近い)に統一する方針です。現在は値渡しですが、Rc / heap 系の型(List, Stack 等)は参照渡しに切り替える予定です。借用チェッカー(check_borrow)は未実装の方針であり、RC ベースの所有権管理で運用する予定です(Rust の借用チェックとは異なる設計)。

列挙型

main.ngs
enum Color {
    Red
    Green
    Blue
}

ジェネリクス型

main.ngs
struct Vec2 {
    x: f32
    y: f32
}
ロードマップ(未実装)

Vec2<T> のようなジェネリクス構造体や class / interface / trait は未実装です。型パラメータは List<i32> 以外では限定的です。実用法は struct Vec2 { x: f32 y: f32 } のような具体的な型で定義してください。


エラーハンドリング

Result 型(enum で自作)

main.ngs
enum Result { Ok Err }

fn divide(a: f64, b: f64) -> Result {
    if b == 0.0 {
        return Result.Err
    }
    return Result.Ok
}
ロードマップ(未実装)

組み込みの Result<T, E> 型は存在せず、? 演算子(エラー伝播)も未実装です。エラーハンドリングが必要な場合は enum で自分で定義し、if 文で分岐します。


ポインタ / unsafe

ポインタと unsafe ブロック

main.ngs
fn read(ptr: *i32) -> i32 {
    unsafe { return *ptr }
}
var x = 42
val p = &x as *i32
println(read(p))
現行仕様(v0.2.0)

ポインタは *T 形式、アドレス取得は &x as *T、参照外しは unsafe { *ptr } を使います。ptr-> は未対応なので *ptr と整数演算で代替してください。

Rc (参照カウント)

main.ngs
val data = Rc.new(Data { x: 10 })
val data2 = data  // 参照の共有
現行仕様(v0.2.0)

Rc.new(値) / .get() は存在しますが、.get() の戻り値が意図と異なる場合がある既知の不具合があります。当面は構造体 + 値渡しを推奨します。


モジュール

import(未実装)

main.ngs
// import は未実装(ロードマップ)
// 複数ファイルへの分割はできない
ロードマップ(未実装)

import は未実装です。"std:io" などの標準モジュールも存在しないため、import "std:io" のような書き方はできません。複数ファイルの分割は現行では行えません。

エクスポート(Wasm / C 向け)

main.ngs
export "C" fn add(a: i32, b: i32) -> i32 {
    return a + b
}
現行仕様(v0.2.0)

export は関数宣言の前置としてのみ使用できます(Wasm / C 向け)。正しい書き方は export "C" fn add(...) -> i32 { ... } の形です。export fn という書き方は誤りです。Wasm 出力は nagiscript wasm main.ngs [-o PATH] でサポートされています。

extern(C 関数の宣言)

main.ngs
extern "C" fn strlen(s: *u8) -> i32
補足

C 標準関数は extern "C" fn で宣言して利用できます。std:math / std:fs / std:args / std:async / std:net などのモジュールはすべて未実装(ロードマップ)です。


コメント

main.ngs
// 単一行コメント

/*
   複数行コメント
*/

fn greet(name: string) -> string {
    return name
}

演算子

算術演算子

演算子 説明 例
+ 加算 a + b
- 減算 a - b
* 乗算 a * b
/ 除算 a / b
% 剰余 a % b
補足

算術演算子(+ - * / %)は数値に対して正常に動作します。ただし文字列の + 連結は使えません。詳細は「演算子リファレンス」を参照してください。

比較演算子

演算子 説明 例
== 等しい a == b
!= 等しくない a != b
< 小さい a < b
> 大きい a > b
<= 以下 a <= b
>= 以上 a >= b

論理演算子

演算子 説明 例
and 論理AND a and b
or 論理OR a or b
not 論理NOT not a
現行仕様(v0.2.0)

論理演算は and or not を使用します。&& / || / ! は使えません。

その他の演算子

演算子 説明 例
-> 戻り値型の記法(関数定義) fn f() -> i32
& アドレス取得 &x as *i32
* 参照外し(unsafe 内) *ptr
as 型変換 x as f64
現行仕様(v0.2.0)

-> は関数定義での戻り値型の記法としてのみ使用します(fn name(...) -> 型)。ptr->(ポインタ経由のメンバアクセス)は未対応です。?(エラー伝播)も未実装です。詳細は「演算子リファレンス」を参照してください。