Skip to content

Latest commit

 

History

History
604 lines (455 loc) · 21.5 KB

File metadata and controls

604 lines (455 loc) · 21.5 KB

Smalruby 日本語モード(DNCL)言語仕様

このドキュメントは、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 との違い を参照してください。

1. 概要

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) / / / 末尾コロンは復元されません)。

標準 DNCL(DNCLv2)との主な違い

DNCLv2 形式の構文は pre-processor がサポート するため、コピペで実行可能です。turn-around した結果は Smalruby 形式に正規化されます。

  • ブロック終端:
    • DNCLv2: インデント戻り(または マーカー)で暗黙終了
    • Smalruby: を実行する / を繰り返す / と定義する の日本語キーワードで明示終了
    • DNCLv2 入力時: pre-processor が の数だけ Smalruby の終端キーワードを自動挿入
  • 条件分岐の末尾コロン:
    • DNCLv2: もし 条件 ならば:
    • Smalruby: もし 条件 ならば(コロンなし)
    • DNCLv2 入力時: pre-processor がコロンを削除
  • 繰り返す 接尾辞:
    • DNCLv2: 条件 の間繰り返す: / i を ... 増やしながら繰り返す:
    • Smalruby: 条件 の間 / i を ... 増やしながら
    • DNCLv2 入力時: pre-processor が 繰り返す 接尾辞を削除
  • 関数定義:
    • DNCLv2: 名前(引数) を定義する: ...
    • Smalruby: 関数 名前(引数) ... と定義する
    • DNCLv2 入力時: pre-processor が opener と を変換
  • 論理演算子:
    • 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: a = X , b = Y
    • Smalruby: 2 行に分けて記述
    • DNCLv2 入力時: pre-processor が複数行に分割
  • その他:
    • 内部的に Scratch ブロックに変換されるため、使用できる機能が Scratch の範囲に限定される
    • 変数に @$ プレフィックスは使えない(Ruby の変数記法は自動的に処理される)

詳細な対応一覧は docs/dncl/README.md の「DNCLv2 互換」セクションを参照してください。

2. プログラム構造

トップレベル構造

DNCL モードのプログラムは、文(Statement)の連続で構成されます。class 定義や module 定義は使用しません。

# 変数の初期化
a = 0

# メインロジック
もし a > 0 ならば
  表示する(a)
を実行する

インデント

ブロック構造はインデントで表現します。制御構造の内部は 2 スペースのインデントが推奨されます。

もし a > 0 ならば
  表示する("正の数")
そうでなければ
  表示する("正でない")
を実行する

コメント

# 以降が行コメントになります。

# これはコメントです
a = 1 # 行末コメント

3. データ型

リテラル

構文 備考
整数 数字の並び 42, 0, -5
浮動小数点数 数字.数字 3.14, 1.0
文字列 "..." または 「...」 "hello", 「テスト」 「」"" に自動変換
真偽値 / , Ruby の true / false に変換
配列 [値1, 値2, ...] [1, 5, 10]

文字列リテラル

ダブルクォート "..." と日本語カギカッコ 「...」 の両方が使えます。カギカッコはトランスパイル時にダブルクォートに変換されます。

a = "hello"
b = 「こんにちは」  # → "こんにちは" に変換

4. 変数

命名規則

先頭文字 内部変換 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]  # 配列の初期化

5. 演算子

算術演算子

演算子 説明 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

注意: かつまたはでない はスペースで区切る必要があります。

6. 制御構造

条件分岐(もし〜ならば)

もし 条件 ならば
  文...
を実行する

ならならば の両方が使えます。ラウンドトリップ変換では ならば に正規化されます。

if-else

もし 条件 ならば
  文...
そうでなければ
  文...
を実行する

if-elsif-else

もし 条件1 ならば
  文1...
そうでなくもし 条件2 ならば
  文2...
そうでなければ
  文3...
を実行する

繰り返し(条件ループ)

条件の間繰り返す(while ループ)

条件 の間
  文...
を繰り返す

例:

a > 0 の間
  a = a - 1
を繰り返す

範囲繰り返し(for ループ)

昇順(増やしながら):

変数 を 開始値 から 終了値 まで 増分 ずつ増やしながら
  文...
を繰り返す

例:

i を 1 から 10 まで 1 ずつ増やしながら
  表示する(i)
を繰り返す

降順(減らしながら):

変数 を 開始値 から 終了値 まで 減分 ずつ減らしながら
  文...
を繰り返す

例:

i を 10 から 0 まで 1 ずつ減らしながら
  表示する(i)
を繰り返す

注意: 終了値は含まれます(inclusive)。1 から 10 まで は 1, 2, 3, ..., 10 を繰り返します。

ブロック終端キーワード

制御構造の種類に応じて、異なる終端キーワードを使います。

終端キーワード 対象
を実行する もし〜ならば(条件分岐)
を繰り返す の間(while ループ)、ずつ増やしながら/減らしながら(for ループ)
と定義する 関数〜(関数定義)

7. 関数

関数定義

関数 関数名(引数1, 引数2)
  文...
と定義する

例:

関数 add(a, b)
  返す a + b
と定義する

戻り値

返す 式

例:

関数 f(x)
  返す x * 2
と定義する

8. 組み込み関数

入出力

関数 説明 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      # 要素の代入

9. ブロックパレット(使用可能なブロック)

DNCL モードでは、Scratch のブロックパレットから使用できるブロックが制限されます。

完全に非表示のカテゴリ

  • 動き(Motion) — 非表示
  • 音(Sound) — 非表示
  • イベント(Events) — 非表示(DNCL にはイベント概念がない)

使用可能なブロック

カテゴリ 使用可能なブロック DNCL 構文との対応
制御 〜回繰り返す, もし〜なら, もし〜でなければ, 〜まで繰り返す for ループ, もし, もし〜そうでなければ, 〜の間
演算 すべて 算術・比較・論理演算子
見た目 〜と〜秒言うsay for N secs)のみ 表示する()
調べる 〜と聞いて待つask), 答えanswer)のみ 【外部からの入力】
変数 すべて(変数の作成、代入、変化、表示/非表示) 変数代入
リスト すべて(追加、削除、挿入、置換、取得、検索、長さ、含む、空判定) 配列操作
ブロック定義 すべて(関数定義、関数呼び出し、引数) 関数〜と定義する

10. エディタ機能

シンタックスハイライト

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 ずつ減らしながら

を繰り返す
条件の間繰り返す 条件 の間

を繰り返す
関数定義 関数 名前(引数)

と定義する
表示する 表示する()
【外部からの入力】 変数 = 【外部からの入力】
要素数 要素数(配列名)
整数 整数(値)
文字列 文字列(値)
乱数 乱数(範囲)

括弧の自動閉じ

以下のペアが自動で閉じられます:

  • (), [], {}
  • "", ''
  • 「」, 【】

11. DNCLv2 との違い

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 モードは、以下のアーキテクチャで動作します:

  1. 双方向トランスパイル: DNCL ↔ Ruby の相互変換が可能(ラウンドトリップ対応)
  2. ソースマップ: 【外部からの入力】 が 2 行に展開される際の行番号マッピングを管理
  3. バリデーション: @$ の禁止文字チェックをトランスパイル前に実行
  4. 配列名の自動検出: ソース全体をスキャンして大文字変数の配列/スカラー判定を行う

12. サポートされていない構文

以下の構文は日本語モード(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 にはあるが未対応)

13. 完全なサンプルプログラム

FizzBuzz

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 でない ならば
  表示する("見つかりませんでした")
を実行する