Files
hakorune/docs/private/ideas/other/dual-mode-design.md

361 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Nyash 2モード設計スクリプトモード vs アプリケーションモード
## 🎯 設計理念
Nyashは「明示性重視」と「使いやすさ」の両方を実現するため、**2つの実行モード**を永続的にサポートする。移行や非推奨化は行わず、それぞれのモードが異なる用途で輝く設計とする。
## 📊 モード比較
### スクリプトモードScript Mode
```nyash
// ファイルhello.nyash
name = "Nyash"
count = 42
print("Hello, " + name + "!")
print("The answer is " + count)
// 関数も自由に定義
function greet(who) {
print("Greetings, " + who)
}
greet("World")
```
### アプリケーションモードApplication Mode
```nyash
// ファイルapp.nyash
static box Main {
init { name, count }
main() {
me.name = "Nyash"
me.count = 42
me.greet()
}
greet() {
print("Hello, " + me.name + "!")
print("The answer is " + me.count)
}
}
```
## 🔍 自動検出ルール
### 基本原則:「見た目で分かる」
1. **`static box`が1つでもある** → アプリケーションモード
2. **`static box`が1つもない** → スクリプトモード
3. **明示的な指定は不要**(ファイル内容で自動判定)
### 検出アルゴリズム
```rust
fn detect_mode(ast: &AST) -> ExecutionMode {
// ASTを走査してstatic boxの存在をチェック
for node in ast.walk() {
match node {
ASTNode::StaticBoxDeclaration { .. } => {
return ExecutionMode::Application;
}
_ => continue,
}
}
ExecutionMode::Script
}
```
## 🌟 各モードの特徴
### スクリプトモード
#### 利点
- **素早いプロトタイピング** - アイデアをすぐ試せる
- **学習曲線が緩やか** - 初心者に優しい
- **REPL完全互換** - コピペで動く
- **ワンライナー対応** - `nyash -e "print(2+2)"`
#### 変数スコープ
```nyash
// グローバルスコープに直接定義
x = 10
y = 20
// 関数内でもアクセス可能
function sum() {
return x + y // グローバル変数を参照
}
// ローカル変数
function calculate() {
local temp = 100 // 関数ローカル
return temp + x
}
```
#### エラーハンドリング
```nyash
// 未定義変数アクセス → 実行時エラー
print(undefined_var) // Runtime Error: undefined variable 'undefined_var'
// 型エラーも実行時
x = "hello"
y = x + 10 // Runtime Error: cannot add String and Integer
```
### アプリケーションモード
#### 利点
- **明示的な変数管理** - どこで何が定義されているか明確
- **静的解析可能** - IDEサポートが充実
- **大規模開発対応** - チーム開発で威力を発揮
- **名前空間の分離** - static box単位でスコープ管理
#### 変数スコープ
```nyash
static box Calculator {
init { x, y, result } // 必ず宣言
calculate() {
// me.を通じてアクセス(明示的)
me.result = me.x + me.y
// ローカル変数
local temp = me.result * 2
return temp
}
}
// ❌ エラー:グローバル変数は定義できない
global_var = 10 // Error: Global variables not allowed in application mode
```
#### コンパイル時チェック
```nyash
static box TypedCalc {
init { value }
setValue(v) {
// 将来的に型推論や型チェックも可能
me.value = v
}
calculate() {
// 未定義フィールドアクセス → コンパイルエラー
return me.undefined_field // Error: 'undefined_field' not declared in init
}
}
```
## 🚀 REPL統合
### REPLの動作
```bash
$ nyash
Nyash REPL v1.0 (Script Mode)
> x = 42
> print(x)
42
> function double(n) { return n * 2 }
> print(double(x))
84
# アプリケーションモードのコードも貼り付け可能
> static box Counter {
. init { count }
. increment() { me.count = me.count + 1 }
. }
> c = new Counter()
> c.increment()
> print(c.count)
1
```
### モード切り替え
```bash
# 通常起動(スクリプトモード)
$ nyash
# アプリケーションモードでREPL起動将来実装
$ nyash --app-mode
Nyash REPL v1.0 (Application Mode)
> x = 42 # Error: Global variables not allowed
> static box Main { ... } # OK
```
## 📝 実装詳細
### パーサーの拡張
```rust
pub struct Parser {
mode: ExecutionMode,
// スクリプトモードでは緩い解析
// アプリケーションモードでは厳格な解析
}
impl Parser {
pub fn parse(&mut self, source: &str) -> Result<AST, ParseError> {
let ast = self.parse_initial(source)?;
self.mode = detect_mode(&ast);
match self.mode {
ExecutionMode::Script => self.validate_script_mode(&ast),
ExecutionMode::Application => self.validate_app_mode(&ast),
}
}
}
```
### インタープリターの対応
```rust
impl Interpreter {
pub fn execute(&mut self, ast: &AST, mode: ExecutionMode) -> Result<Value, RuntimeError> {
match mode {
ExecutionMode::Script => {
// グローバル変数を許可
self.allow_globals = true;
self.execute_script(ast)
}
ExecutionMode::Application => {
// グローバル変数を禁止
self.allow_globals = false;
self.execute_application(ast)
}
}
}
}
```
## 🎨 ベストプラクティス
### いつスクリプトモードを使うか
1. **データ処理スクリプト**
```nyash
data = readFile("input.csv")
lines = data.split("\n")
for line in lines {
fields = line.split(",")
print(fields[0] + ": " + fields[1])
}
```
2. **設定ファイル**
```nyash
# config.nyash
server_host = "localhost"
server_port = 8080
debug_mode = true
```
3. **テストコード**
```nyash
# test_math.nyash
assert(2 + 2 == 4)
assert(10 / 2 == 5)
print("All tests passed!")
```
### いつアプリケーションモードを使うか
1. **Webアプリケーション**
```nyash
static box WebServer {
init { port, routes }
start() {
me.port = 8080
me.routes = new MapBox()
me.setupRoutes()
me.listen()
}
}
```
2. **ゲーム開発**
```nyash
static box Game {
init { player, enemies, score }
main() {
me.initialize()
loop(me.isRunning()) {
me.update()
me.render()
}
}
}
```
3. **ライブラリ開発**
```nyash
static box MathLib {
init { precision }
static factorial(n) {
if n <= 1 { return 1 }
return n * MathLib.factorial(n - 1)
}
}
```
## 🔮 将来の拡張
### 混在モード(検討中)
```nyash
#!script
// ファイルの最初の部分はスクリプトモード
config = loadConfig()
debug = true
#!application
// ここからアプリケーションモード
static box Main {
init { config }
main() {
// スクリプト部分の変数を参照できる?
me.config = ::config // グローバルスコープ参照構文
}
}
```
### プロジェクト設定
```toml
# nyash.toml
[project]
name = "my-app"
default_mode = "application" # プロジェクト全体のデフォルト
[scripts]
# 特定のファイルはスクリプトモードで実行
mode = "script"
files = ["scripts/*.nyash", "tests/*.nyash"]
```
## 🌈 他言語との比較
### Python
- **類似点**: REPLとファイル実行で同じ動作
- **相違点**: Nyashはモードを明確に分離
### JavaScript/TypeScript
- **類似点**: strictモードの概念
- **相違点**: Nyashは見た目で判定`"use strict"`不要)
### C#
- **優位性**:
- トップレベルステートメントより柔軟
- 明示的なモード分離で混乱なし
- REPLとの完全な統合
### Ruby
- **類似点**: スクリプトとクラスベースの両対応
- **相違点**: Nyashはより明確なモード分離
## 🎯 まとめ
Nyashの2モード設計は
1. **移行不要** - 両モード永続サポート
2. **自動判定** - ファイル内容で自動切り替え
3. **REPL対応** - 同じルールで直感的
4. **いいとこ取り** - 用途に応じて最適なモードを選択
この設計により、Nyashは「**初心者に優しく、プロに強力**」な言語となる。