================================================================================ Nyash 糖衣構文 可逆フォーマッター仕様 2025-09-03 ================================================================================ 【コンセプト】 極限短縮構文 ⇄ 標準構文の相互変換ツール(Nyashで実装) ================================================================================ 1. 基本設計 ================================================================================ box NyashFormatter { mode: FormatterMode // Compact | Standard | Verbose birth() { me.mode = FormatterMode.Standard } // 短縮 → 標準への展開 expand(code: StringBox) -> StringBox { code |> tokenize |> expandSugar |> format(me.mode) |> toString } // 標準 → 短縮への圧縮 compact(code: StringBox) -> StringBox { code |> tokenize |> compactSugar |> minify |> toString } } ================================================================================ 2. 変換規則マッピング ================================================================================ // 糖衣構文の変換ルールを定義 static box SugarRules { // 暗黙変数の展開 expandImplicit(ast) { peek ast { ImplicitVar("$_") => { // コンテキストから引数名を推論 local argName = inferArgumentName(ast.context) Identifier(argName) } ImplicitVar("$1") => Identifier("_arg1") ImplicitVar("$2") => Identifier("_arg2") else => ast } } // パイプラインの展開 expandPipeline(ast) { peek ast { Pipeline(expr, func) => { // x |> f(a,b) → f(a, b, x) peek func { Call(name, args) => Call(name, [...args, expr]) PropertyAccess(prop) => PropertyAccess(expr, prop) else => Call(func, [expr]) } } else => ast } } // 短縮演算子の展開 expandOperators(ast) { peek ast { MapOp(list, expr) => { // list /: expr → list.map(expr) MethodCall(list, "map", [expandLambda(expr)]) } FilterOp(list, expr) => { // list \: expr → list.filter(expr) MethodCall(list, "filter", [expandLambda(expr)]) } else => ast } } } ================================================================================ 3. フォーマットモード ================================================================================ // 3段階の詳細度 enum FormatterMode { Compact, // 極限短縮 Standard, // 標準的な記法 Verbose // 初心者向け詳細 } // モード別の変換例 box FormatExamples { showModes() { local code = "[$.name for users if $.age > 18]" print("=== Compact (極限) ===") print(code) print("=== Standard (標準) ===") local standard = formatter.expand(code) print(standard) // [user.name for user in users if user.age > 18] print("=== Verbose (詳細) ===") local verbose = formatter.expandVerbose(code) print(verbose) // local result = new ArrayBox() // for user in users { // if user.age > 18 { // result.push(user.name) // } // } } } ================================================================================ 4. 実装例:主要な糖衣構文の変換 ================================================================================ // 1. 暗黙変数 "list /: {$_*2}" ↓ expand "list.map(fn(item) { return item * 2 })" // 2. パイプライン "input |> trim |> upper" ↓ expand "upper(trim(input))" // 3. null安全 "user?.profile?.name ?? 'Anonymous'" ↓ expand "peek user { null => 'Anonymous' else => peek user.profile { null => 'Anonymous' else => peek user.profile.name { null => 'Anonymous' else => user.profile.name } } }" // 4. キーワード短縮 "l x = 42; ^ x*2" ↓ expand "local x = 42 return x * 2" // 5. 演算子セクション "nums /: (+1)" ↓ expand "nums.map(fn(x) { return x + 1 })" // 6. リスト内包 "[x*x for x in nums if x%2==0]" ↓ expand (Standard) "nums.filter(fn(x) { return x % 2 == 0 }) .map(fn(x) { return x * x })" ↓ expand (Verbose) "local result = new ArrayBox() for x in nums { if x % 2 == 0 { result.push(x * x) } } result" ================================================================================ 5. 使用例:コマンドラインツール ================================================================================ // nyashfmt.hako - フォーマッターCLI static box Main { main(args) { local formatter = new NyashFormatter() local mode = args[1] ?? "standard" local file = args[2] peek mode { "expand" => { local code = FileBox.read(file) local expanded = formatter.expand(code) print(expanded) } "compact" => { local code = FileBox.read(file) local compacted = formatter.compact(code) print(compacted) } "check" => { // 可逆性チェック local original = FileBox.read(file) local round = original |> formatter.compact |> formatter.expand |> formatter.compact if round == formatter.compact(original) { print("✅ 可逆変換OK") } else { print("❌ 変換エラー:情報が失われています") } } else => { print("Usage: nyashfmt [expand|compact|check] ") } } } } ================================================================================ 6. エディタ統合 ================================================================================ // VSCode/エディタ向けのフォーマッター統合 box EditorFormatter { // 選択範囲の展開/圧縮 formatSelection(text, mode) { local formatter = new NyashFormatter() peek mode { "toggle" => { // 自動判定:短縮記法が含まれていれば展開、なければ圧縮 if me.hasShortSyntax(text) { formatter.expand(text) } else { formatter.compact(text) } } "expand" => formatter.expand(text) "compact" => formatter.compact(text) else => text } } // ホバー時のツールチップ表示 showExpanded(position) { local ast = me.getAstAt(position) local expanded = SugarRules.expandNode(ast) // ツールチップに展開形を表示 return "展開形: " + expanded.toString() } } ================================================================================ 7. 学習モード(初心者支援) ================================================================================ box LearningMode { // 段階的に糖衣構文を導入 suggestSugar(code) { local suggestions = new ArrayBox() // パターンマッチで改善可能な箇所を検出 if code.contains("list.map(fn(x) { return") { suggestions.push({ original: "list.map(fn(x) { return x * 2 })", sugar: "list /: {$_*2}", explanation: "/: は map の短縮記法です" }) } if code.contains("if x != null") { suggestions.push({ original: "if x != null { x.method() } else { null }", sugar: "x?.method()", explanation: "?. でnullチェックを簡潔に" }) } return suggestions } } ================================================================================ 8. 設定ファイル ================================================================================ // .hakofmt.json - プロジェクト別設定 { "mode": "standard", "rules": { "implicit_variable": true, // $_ を許可 "short_keywords": true, // l, ^, fn を許可 "unicode_operators": false, // λ, → は使わない "pipeline": true, // |> を許可 "list_comprehension": true, // [...for...] を許可 "operator_sections": true // (+1) を許可 }, "expand_on_save": false, // 保存時に展開 "check_reversibility": true // 可逆性チェック } ================================================================================