このドキュメントは、smalruby3-editor の 日本語モード(DNCLモード) で対応している構文と機能を定義します。
ソースコードの packages/scratch-gui/src/lib/dncl/(DNCL ↔ Ruby トランスパイラ)と packages/scratch-gui/src/containers/ruby-tab/dncl-mode.js(Monaco エディタ言語定義)に基づいています。
注意: 本ドキュメントは smalruby3-editor における実装を正として記載しています。大学入学共通テスト手順記述標準言語(DNCLv2)とは異なる点があります。差分は DNCLv2 との違い を参照してください。
smalruby の日本語モード(DNCLモード)は、大学入学共通テスト手順記述標準言語(DNCL)を参考にした日本語ベースのプログラミング言語です。日本語で記述したコードは内部的に Ruby コードにトランスパイルされ、さらに Scratch ブロックに変換されて実行されます。
DNCL コード → (dncl-v2-preprocessor.js) → Smalruby DNCL → (dncl-to-ruby.js) → Ruby コード → (ruby-to-blocks-converter) → Scratch ブロック → 実行
最初に DNCLv2 pre-processor が DNCLv2 形式の構文(行番号、| / ⎿ インデントマーカー、末尾コロン、の間繰り返す / 増やしながら繰り返す の 繰り返す 接尾辞、同一行複数代入、and / or、関数定義 opener 形式 NAME(ARGS) を定義する)を Smalruby DNCL に正規化します。Smalruby DNCL の入力はそのまま通過します。
ブロック → Ruby → DNCL の逆方向の変換も可能です(ruby-to-dncl.js)。turn-around 後は Smalruby DNCL 形式に正規化されます(DNCLv2 形式の (N) / | / ⎿ / 末尾コロンは復元されません)。
DNCLv2 形式の構文は pre-processor がサポート するため、コピペで実行可能です。turn-around した結果は Smalruby 形式に正規化されます。
- ブロック終端:
- DNCLv2: インデント戻り(または
⎿マーカー)で暗黙終了 - Smalruby:
を実行する/を繰り返す/と定義するの日本語キーワードで明示終了 - DNCLv2 入力時: pre-processor が
⎿の数だけ Smalruby の終端キーワードを自動挿入
- DNCLv2: インデント戻り(または
- 条件分岐の末尾コロン:
- DNCLv2:
もし 条件 ならば: - Smalruby:
もし 条件 ならば(コロンなし) - DNCLv2 入力時: pre-processor がコロンを削除
- DNCLv2:
繰り返す接尾辞:- DNCLv2:
条件 の間繰り返す:/i を ... 増やしながら繰り返す: - Smalruby:
条件 の間/i を ... 増やしながら - DNCLv2 入力時: pre-processor が
繰り返す接尾辞を削除
- DNCLv2:
- 関数定義:
- DNCLv2:
名前(引数) を定義する:...⎿ - Smalruby:
関数 名前(引数)...と定義する - DNCLv2 入力時: pre-processor が opener と
⎿を変換
- DNCLv2:
- 論理演算子:
- DNCLv2:
a > 0 and b == 1/a > 0 or b > 0 - Smalruby:
a > 0 かつ b == 1/a > 0 または b > 0 - DNCLv2 入力時: pre-processor が whole-word 一致で変換
- DNCLv2:
- 同一行複数代入:
- DNCLv2:
a = X , b = Y - Smalruby: 2 行に分けて記述
- DNCLv2 入力時: pre-processor が複数行に分割
- DNCLv2:
- その他:
- 内部的に Scratch ブロックに変換されるため、使用できる機能が Scratch の範囲に限定される
- 変数に
@や$プレフィックスは使えない(Ruby の変数記法は自動的に処理される)
詳細な対応一覧は docs/dncl/README.md の「DNCLv2 互換」セクションを参照してください。
DNCL モードのプログラムは、文(Statement)の連続で構成されます。class 定義や module 定義は使用しません。
# 変数の初期化
a = 0
# メインロジック
もし a > 0 ならば
表示する(a)
を実行する
ブロック構造はインデントで表現します。制御構造の内部は 2 スペースのインデントが推奨されます。
もし a > 0 ならば
表示する("正の数")
そうでなければ
表示する("正でない")
を実行する
# 以降が行コメントになります。
# これはコメントです
a = 1 # 行末コメント
| 型 | 構文 | 例 | 備考 |
|---|---|---|---|
| 整数 | 数字の並び |
42, 0, -5 |
|
| 浮動小数点数 | 数字.数字 |
3.14, 1.0 |
|
| 文字列 | "..." または 「...」 |
"hello", 「テスト」 |
「」 は "" に自動変換 |
| 真偽値 | 真 / 偽 |
真, 偽 |
Ruby の true / false に変換 |
| 配列 | [値1, 値2, ...] |
[1, 5, 10] |
ダブルクォート "..." と日本語カギカッコ 「...」 の両方が使えます。カギカッコはトランスパイル時にダブルクォートに変換されます。
a = "hello"
b = 「こんにちは」 # → "こんにちは" に変換
| 先頭文字 | 内部変換 | 例 | Ruby 変換後 |
|---|---|---|---|
小文字 (a-z) |
インスタンス変数 | a, score |
@a, @score |
| 大文字(スカラー値) | 名前付き変数 | A, Max |
@_var_A_, @_var_Max_ |
| 大文字(配列値) | 名前付き配列 | Kouka, Data |
@_array_Kouka_, @_array_Data_ |
大文字で始まる変数名が配列かスカラーかは、ソースコード内で配列リテラルの代入(X = [...])、配列アクセス(X[i])、または 要素数(X) の使用があるかどうかで自動判定されます。
- ASCII 英字(
a-z,A-Z)、数字(0-9)、アンダースコア(_) - ひらがな(
\u3040-\u309F)、カタカナ(\u30A0-\u30FF)、漢字(\u4E00-\u9FFF)
変数名に @ や $ を使うことはできません。使用した場合、バリデーションエラーが表示されます。
# ❌ エラー: 日本語モードでは変数に「@」は使えません
@a = 10
# ✅ 正しい書き方
a = 10
| 構文 | 例 | Ruby 変換後 |
|---|---|---|
変数 = 式 |
a = 10 |
@a = 10 |
変数 ← 式 |
a ← 10 |
@a = 10 |
矢印 ← による代入も使用できます(= と同等)。
a = 10 # 通常の代入
A ← 3 # 矢印による代入
Kouka = [1, 5, 10] # 配列の初期化
| 演算子 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
+ |
加算 / 文字列結合 | a + b |
@a + @b |
- |
減算 | a - 1 |
@a - 1 |
* |
乗算 | a * 2 |
@a * 2 |
/ |
除算 | a / 3 |
@a / 3 |
÷ |
除算(全角) | a ÷ 3 |
@a / 3 |
// |
整数除算 | 10 // 3 |
(10 / 3).to_i |
% |
剰余 | a % 2 |
@a % 2 |
| 演算子 | 説明 | 例 |
|---|---|---|
= |
等しい(条件式内) | a = 10(※文脈依存) |
== |
等しい | a == 10 |
!= |
等しくない | a != 0 |
< |
小さい | a < 10 |
> |
大きい | a > 0 |
<= |
以下 | a <= 10 |
>= |
以上 | a >= 0 |
≦ |
以下(全角) | a ≦ 10 |
≧ |
以上(全角) | a ≧ 0 |
注意:
=の代入と比較の区別は文脈(文の先頭 = 代入、条件式内 = 比較)で判断されますが、曖昧さを避けるため条件式では==の使用を推奨します。
| 演算子 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
かつ |
論理積 | a > 0 かつ b < 10 |
@a > 0 && @b < 10 |
または |
論理和 | a > 0 または b > 0 |
@a > 0 || @b > 0 |
でない |
論理否定(後置) | a でない |
!@a |
注意:
かつ、または、でないはスペースで区切る必要があります。
もし 条件 ならば
文...
を実行する
なら と ならば の両方が使えます。ラウンドトリップ変換では ならば に正規化されます。
もし 条件 ならば
文...
そうでなければ
文...
を実行する
もし 条件1 ならば
文1...
そうでなくもし 条件2 ならば
文2...
そうでなければ
文3...
を実行する
条件 の間
文...
を繰り返す
例:
a > 0 の間
a = a - 1
を繰り返す
昇順(増やしながら):
変数 を 開始値 から 終了値 まで 増分 ずつ増やしながら
文...
を繰り返す
例:
i を 1 から 10 まで 1 ずつ増やしながら
表示する(i)
を繰り返す
降順(減らしながら):
変数 を 開始値 から 終了値 まで 減分 ずつ減らしながら
文...
を繰り返す
例:
i を 10 から 0 まで 1 ずつ減らしながら
表示する(i)
を繰り返す
注意: 終了値は含まれます(inclusive)。
1 から 10 までは 1, 2, 3, ..., 10 を繰り返します。
制御構造の種類に応じて、異なる終端キーワードを使います。
| 終端キーワード | 対象 |
|---|---|
を実行する |
もし〜ならば(条件分岐) |
を繰り返す |
の間(while ループ)、ずつ増やしながら/減らしながら(for ループ) |
と定義する |
関数〜(関数定義) |
関数 関数名(引数1, 引数2)
文...
と定義する
例:
関数 add(a, b)
返す a + b
と定義する
返す 式
例:
関数 f(x)
返す x * 2
と定義する
| 関数 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
表示する(式) |
値を表示する | 表示する(a) |
puts(@a) |
【外部からの入力】 |
外部からの入力を受け取る | a = 【外部からの入力】 |
ask("")@a = answer |
表示する は複数の引数を受け取れます。文字列リテラル以外の引数は .to_s が自動付与され、+ で連結された 1 つの吹き出し として表示されます:
表示する(a, b, c) # → puts(@a.to_s + @b.to_s + @c.to_s)
表示する(atai, "は", aida) # → puts(@atai.to_s + "は" + @aida.to_s)
重要 (不可逆性): DNCL
表示する(...)は Ruby ではputs(...)に変換されます (say(..., 1)ではない)。これは「Console に表示する」という意味的にputsの方が表示するに近いためです。sayは Scratch の吹き出し演出を含むため、DNCL の純粋な「表示」とは異なるとして区別しています。詳細は Block ↔ Ruby ↔ DNCL 変換マトリクス を参照。
【外部からの入力】 は代入文の右辺で使用し、Ruby では 2 行に展開されます:
a = 【外部からの入力】
# ↓ Ruby 変換後
# ask_and_wait("")
# @a = answer
| 関数 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
整数(式) |
整数に変換(小数点以下切り捨て) | 整数(x) |
@x.to_i |
文字列(式) |
文字列に変換 | 文字列(x) |
@x.to_s |
| 関数 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
乱数(n) |
乱数を生成 | 乱数(10) |
rand(10) |
四捨五入(式) |
四捨五入 | 四捨五入(3.7) |
3.7.round |
切り捨て(式) |
小数点以下切り捨て | 切り捨て(3.7) |
3.7.floor |
切り上げ(式) |
小数点以下切り上げ | 切り上げ(3.2) |
3.2.ceil |
絶対値(式) |
絶対値 | 絶対値(-5) |
(-5).abs |
平方根(式) |
平方根 | 平方根(9) |
Math.sqrt(9) |
| 関数 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
含む(文字列, 検索文字列) |
文字列に検索文字列が含まれるか | 含む("hello", "ell") |
"hello".include?("ell") |
| 関数 | 説明 | 例 | Ruby 変換後 |
|---|---|---|---|
要素数(配列) |
配列/文字列の要素数(長さ)を取得 | 要素数(Kouka) |
@_array_Kouka_.length |
配列の要素にはインデックス(0 起点)でアクセスします。
Kouka = [1, 5, 10]
a = Kouka[0] # → 1
Kouka[0] = 100 # 要素の代入
DNCL モードでは、Scratch のブロックパレットから使用できるブロックが制限されます。
- 動き(Motion) — 非表示
- 音(Sound) — 非表示
- イベント(Events) — 非表示(DNCL にはイベント概念がない)
| カテゴリ | 使用可能なブロック | DNCL 構文との対応 |
|---|---|---|
| 制御 | 〜回繰り返す, もし〜なら, もし〜でなければ, 〜まで繰り返す |
for ループ, もし, もし〜そうでなければ, 〜の間 |
| 演算 | すべて | 算術・比較・論理演算子 |
| 見た目 | 〜と〜秒言う(say for N secs)のみ |
表示する() |
| 調べる | 〜と聞いて待つ(ask), 答え(answer)のみ |
【外部からの入力】 |
| 変数 | すべて(変数の作成、代入、変化、表示/非表示) | 変数代入 |
| リスト | すべて(追加、削除、挿入、置換、取得、検索、長さ、含む、空判定) | 配列操作 |
| ブロック定義 | すべて(関数定義、関数呼び出し、引数) | 関数〜と定義する |
Monaco エディタで以下の要素がハイライトされます:
| 要素 | トークン種別 | 色の例 |
|---|---|---|
| 制御キーワード | keyword |
もし, ならば, を実行する 等 |
| 組み込み関数 | type.identifier |
表示する, 要素数 等 |
| 論理演算子 | keyword.operator |
かつ, または, でない |
| 真偽値 | constant.language |
真, 偽 |
| 入力プレースホルダ | keyword |
【外部からの入力】 |
| 文字列 | string |
"...", 「...」 |
| 数値 | number |
42, 3.14 |
| コメント | comment |
# ... |
| 演算子 | operator |
÷, //, ≦, ≧, ← |
以下のキーワードの後で自動的にインデントが増加します:
なら/ならば(条件分岐の開始)そうでなければ(else 節)そうでなくもし(elsif 節)の間(while ループ)ずつ増やしながら/ずつ減らしながら(for ループ)関数〜(関数定義)
以下のキーワードでインデントが自動的に減少します:
を実行するを繰り返すと定義するそうでなければそうでなくもし
以下のスニペットが入力候補として表示されます:
| トリガー | 展開 |
|---|---|
もし...ならば |
もし 条件 ならば を実行する |
もし...そうでなければ |
もし 条件 ならば そうでなければ を実行する |
繰り返し(増やす) |
i を 1 から 10 まで 1 ずつ増やしながら を繰り返す |
繰り返し(減らす) |
i を 10 から 0 まで 1 ずつ減らしながら を繰り返す |
条件の間繰り返す |
条件 の間 を繰り返す |
関数定義 |
関数 名前(引数) と定義する |
表示する |
表示する() |
【外部からの入力】 |
変数 = 【外部からの入力】 |
要素数 |
要素数(配列名) |
整数 |
整数(値) |
文字列 |
文字列(値) |
乱数 |
乱数(範囲) |
以下のペアが自動で閉じられます:
(),[],{}"",''「」,【】
smalruby3-editor の日本語モードは DNCLv2 を参考にしていますが、以下の点で異なります。
| 項目 | DNCLv2 | smalruby3-editor |
|---|---|---|
| 条件分岐の開始 | もし 条件 ならば: |
もし 条件 ならば(コロンなし) |
| 繰り返しの開始 | 〜の間繰り返す: |
条件 の間(末尾の「繰り返す」とコロンなし) |
| for ループの開始 | 〜ずつ増やしながら繰り返す: |
〜ずつ増やしながら(末尾の「繰り返す」とコロンなし) |
| 関数定義の開始 | 関数名(引数) を定義する: |
関数 関数名(引数)(関数 キーワードが先頭、コロンなし) |
| ブロック終端 | インデント戻りで暗黙終了 | を実行する / を繰り返す / と定義する で明示終了 |
| 代入(自然言語風) | 変数 に 式 を入れる |
未対応(= または ← のみ) |
| 配列宣言 | 要素数 n の配列 A |
未対応(配列リテラル A = [...] で初期化) |
| else 節 | そうでない |
そうでなければ |
| 等価比較 | =(条件式内で比較) |
==(推奨)、= も使用可能だが曖昧 |
| 項目 | DNCLv2 | smalruby3-editor |
|---|---|---|
| 実行環境 | コンソール入出力 | Scratch ステージ上で実行 |
| 入出力 | 表示する(式) で標準出力 |
表示する(式) → say(式, 1) で吹き出し表示 |
| 入力 | 外部からの入力() |
【外部からの入力】(隅付きカッコ記法) |
| 戻り値 | 式 を返す |
返す 式(語順が逆) |
| 整数除算 | // |
//(同じ、.to_i に変換) |
| 全角演算子 | 未定義 | ÷(除算), ≦(以下), ≧(以上), ←(代入)に対応 |
| スコープ | グローバル/ローカル | すべて Scratch のスプライト変数に変換 |
| 動き/音/見た目 | 対象外 | Scratch の一部ブロック(say のみ)が使用可能 |
| 配列操作 | 要素数(A) 等 |
要素数(A) 対応、Scratch のリストブロックも使用可能 |
| イベント駆動 | なし | 旗が押されたとき ブロックを使用可能 |
smalruby3-editor の DNCL モードは、以下のアーキテクチャで動作します:
- 双方向トランスパイル: DNCL ↔ Ruby の相互変換が可能(ラウンドトリップ対応)
- ソースマップ:
【外部からの入力】が 2 行に展開される際の行番号マッピングを管理 - バリデーション:
@や$の禁止文字チェックをトランスパイル前に実行 - 配列名の自動検出: ソース全体をスキャンして大文字変数の配列/スカラー判定を行う
以下の構文は日本語モード(DNCL モード)では使用できません:
- class 定義 / module 定義 / include
- イベントハンドラ(
旗が押されたとき以外) - 動き関連メソッド(
move,turn_right等) - 音関連メソッド(
play,stop_all_sounds等) - 見た目の大部分(
say以外のthink,show,hide等) - 調べるの大部分(
ask/answer以外のtouching?,mouse.x等) self.属性 = 値形式のプロパティ設定- 正規表現
for/eachループloop do...end(無限ループ)unless/case-when- 修飾子 if / unless
super- 複合代入演算子(
+=,-=等) 「変数 に 式 を入れる」形式の自然言語代入(DNCLv2 にはあるが未対応)
i を 1 から 30 まで 1 ずつ増やしながら
もし i % 15 == 0 ならば
表示する("FizzBuzz")
そうでなくもし i % 3 == 0 ならば
表示する("Fizz")
そうでなくもし i % 5 == 0 ならば
表示する("Buzz")
そうでなければ
表示する(i)
を実行する
を繰り返す
Data = [3, 1, 4, 1, 5, 9, 2, 6]
合計 = 0
i を 0 から 要素数(Data) - 1 まで 1 ずつ増やしながら
合計 = 合計 + Data[i]
を繰り返す
表示する(合計)
関数 最大値(a, b)
もし a > b ならば
返す a
そうでなければ
返す b
を実行する
と定義する
x = 【外部からの入力】
y = 【外部からの入力】
表示する(最大値(整数(x), 整数(y)))
Data = [5, 3, 8, 1, 9, 2, 7]
key = 【外部からの入力】
key = 整数(key)
found = 偽
i を 0 から 要素数(Data) - 1 まで 1 ずつ増やしながら
もし Data[i] == key ならば
表示する(文字列(i) + "番目に見つかりました")
found = 真
を実行する
を繰り返す
もし found でない ならば
表示する("見つかりませんでした")
を実行する