fix(joinir): Phase 241-EX - Remove hardcoded 'sum' check from Pattern3
Remove legacy hardcoded 'sum' carrier validation that was blocking array_filter patterns with different accumulator names (e.g., 'out'). Before: Pattern3 required carrier named 'sum' to exist After: Pattern3 uses carrier_info generically (any carrier name works) Test results: - phase49_joinir_array_filter_smoke: PASS ✅ - phase49_joinir_array_filter_fallback: PASS ✅ - phase49_joinir_array_filter_ab_comparison: PASS ✅ - Full suite: 909/909 PASS, 0 FAIL Also: Archive old roadmap documentation (67k lines moved to docs/archive/) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -0,0 +1,448 @@
|
||||
# Codex先生のNyashブラウザーアーキテクチャ提案
|
||||
|
||||
## 質問内容
|
||||
|
||||
Nyashでブラウザーを作り、ネイティブ実行する構想について、技術的な実装方法と革新的なアイデアを求めた。
|
||||
|
||||
## Codex先生の回答
|
||||
|
||||
### 🏗️ アーキテクチャ比較
|
||||
|
||||
#### 1. Chrome拡張機能 + Native Messaging
|
||||
```javascript
|
||||
// manifest.json
|
||||
{
|
||||
"name": "Nyash Browser Extension",
|
||||
"permissions": ["webRequest", "webRequestBlocking", "nativeMessaging"],
|
||||
"host_permissions": ["*://*/*.hako"]
|
||||
}
|
||||
|
||||
// background.js
|
||||
chrome.webRequest.onBeforeRequest.addListener(
|
||||
(details) => {
|
||||
if (details.url.endsWith('.hako')) {
|
||||
// Native hostと通信してNyash VMで実行
|
||||
chrome.runtime.sendNativeMessage('com.hako.runtime',
|
||||
{ command: 'execute', url: details.url },
|
||||
(response) => {
|
||||
// 結果を新しいタブで表示
|
||||
chrome.tabs.update(details.tabId, {
|
||||
url: 'data:text/html;charset=utf-8,' +
|
||||
encodeURIComponent(response.html)
|
||||
});
|
||||
}
|
||||
);
|
||||
return { cancel: true };
|
||||
}
|
||||
},
|
||||
{ urls: ["<all_urls>"] },
|
||||
["blocking"]
|
||||
);
|
||||
```
|
||||
|
||||
**評価**: ⭐⭐⭐
|
||||
- メリット: 実装が簡単、既存ブラウザ活用
|
||||
- デメリット: IPC通信のオーバーヘッド、制限多い
|
||||
|
||||
#### 2. Chromiumソース改造
|
||||
```cpp
|
||||
// content/browser/nyash/nyash_url_loader.cc
|
||||
class NyashURLLoader : public URLLoader {
|
||||
public:
|
||||
void Start() override {
|
||||
if (request_.url.SchemeIs("nyash")) {
|
||||
// Nyash VMを直接呼び出し
|
||||
auto result = RunNyashVM(request_.url.path());
|
||||
|
||||
// レスポンスを生成
|
||||
auto response = network::mojom::URLResponseHead::New();
|
||||
response->mime_type = "text/html";
|
||||
|
||||
client_->OnReceiveResponse(std::move(response));
|
||||
client_->OnStartLoadingResponseBody(
|
||||
CreateDataPipe(result.html));
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**評価**: ⭐⭐
|
||||
- メリット: 完全な制御、最高性能
|
||||
- デメリット: メンテナンス地獄、現実的でない
|
||||
|
||||
#### 3. Tauri統合(推奨)
|
||||
```rust
|
||||
// src-tauri/src/main.rs
|
||||
use tauri::{Manager, Window};
|
||||
use nyash_vm::VM;
|
||||
|
||||
#[tauri::command]
|
||||
async fn execute_nyash(window: Window, code: String) -> Result<Value, String> {
|
||||
let vm = VM::new();
|
||||
|
||||
// プログレス通知
|
||||
window.emit("nyash-compile-start", ()).unwrap();
|
||||
|
||||
match vm.execute(&code) {
|
||||
Ok(result) => {
|
||||
window.emit("nyash-compile-success", &result).unwrap();
|
||||
Ok(result)
|
||||
}
|
||||
Err(e) => {
|
||||
window.emit("nyash-compile-error", &e.to_string()).unwrap();
|
||||
Err(e.to_string())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// カスタムプロトコルハンドラー
|
||||
fn nyash_protocol_handler(app: &AppHandle, request: &Request) -> Response {
|
||||
let path = request.uri().path();
|
||||
|
||||
// .hakoファイルを実行
|
||||
if path.ends_with(".hako") {
|
||||
let code = std::fs::read_to_string(path).unwrap();
|
||||
let vm = VM::new();
|
||||
let result = vm.execute(&code).unwrap();
|
||||
|
||||
return Response::builder()
|
||||
.header("Content-Type", "text/html")
|
||||
.body(result.to_html().into())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
// 通常のファイル
|
||||
Response::builder()
|
||||
.status(404)
|
||||
.body(Vec::new())
|
||||
.unwrap()
|
||||
}
|
||||
```
|
||||
|
||||
### 🚀 革新的実装アイデア
|
||||
|
||||
#### 1. カスタムHTMLエレメント
|
||||
```html
|
||||
<!-- Nyashコードを直接HTMLに埋め込み -->
|
||||
<nyash-app src="todo-app.hako">
|
||||
<template>
|
||||
<div class="todo-list">
|
||||
<nyash-for items="todos" as="todo">
|
||||
<div class="todo-item">{{ todo.text }}</div>
|
||||
</nyash-for>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script type="text/nyash">
|
||||
box TodoApp {
|
||||
init { todos }
|
||||
|
||||
constructor() {
|
||||
me.todos = new ArrayBox()
|
||||
}
|
||||
|
||||
addTodo(text) {
|
||||
me.todos.push({ text: text, done: false })
|
||||
me.render() // 自動的にDOMを更新
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</nyash-app>
|
||||
```
|
||||
|
||||
実装:
|
||||
```javascript
|
||||
// カスタムエレメントの定義
|
||||
class NyashAppElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
this.vm = null;
|
||||
}
|
||||
|
||||
async connectedCallback() {
|
||||
const src = this.getAttribute('src');
|
||||
const script = this.querySelector('script[type="text/nyash"]');
|
||||
|
||||
// Tauri経由でNyash VMを呼び出し
|
||||
const result = await window.__TAURI__.invoke('execute_nyash', {
|
||||
code: script ? script.textContent : '',
|
||||
src: src
|
||||
});
|
||||
|
||||
// 結果をShadow DOMにレンダリング
|
||||
this.shadowRoot.innerHTML = result.html;
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('nyash-app', NyashAppElement);
|
||||
```
|
||||
|
||||
#### 2. 共有メモリUI更新
|
||||
```rust
|
||||
// 高速な共有メモリ経由のUI更新
|
||||
use shared_memory::{Shmem, ShmemConf};
|
||||
|
||||
struct SharedUI {
|
||||
shmem: Shmem,
|
||||
canvas_buffer: *mut u8,
|
||||
}
|
||||
|
||||
impl SharedUI {
|
||||
fn new() -> Self {
|
||||
let shmem = ShmemConf::new()
|
||||
.size(1920 * 1080 * 4) // RGBA buffer
|
||||
.flink("nyash-ui-buffer")
|
||||
.create().unwrap();
|
||||
|
||||
Self {
|
||||
canvas_buffer: shmem.as_ptr(),
|
||||
shmem,
|
||||
}
|
||||
}
|
||||
|
||||
// Nyash VMから直接描画
|
||||
fn draw_rect(&mut self, x: i32, y: i32, w: i32, h: i32, color: u32) {
|
||||
unsafe {
|
||||
// 共有メモリに直接描画
|
||||
let buffer = self.canvas_buffer as *mut u32;
|
||||
for dy in 0..h {
|
||||
for dx in 0..w {
|
||||
let offset = ((y + dy) * 1920 + (x + dx)) as isize;
|
||||
*buffer.offset(offset) = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
JavaScript側:
|
||||
```javascript
|
||||
// 共有メモリからCanvasに高速転送
|
||||
const shmem = new SharedArrayBuffer(1920 * 1080 * 4);
|
||||
const uint32View = new Uint32Array(shmem);
|
||||
|
||||
function updateCanvas() {
|
||||
const imageData = ctx.createImageData(1920, 1080);
|
||||
const data32 = new Uint32Array(imageData.data.buffer);
|
||||
|
||||
// 共有メモリから一括コピー(超高速)
|
||||
data32.set(uint32View);
|
||||
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
requestAnimationFrame(updateCanvas);
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. WebGPU統合
|
||||
```nyash
|
||||
// NyashでWebGPUを使った高速レンダリング
|
||||
box GPURenderer from WebGPUBox {
|
||||
init { device, pipeline, vertices }
|
||||
|
||||
constructor() {
|
||||
me.device = me.requestDevice()
|
||||
me.pipeline = me.createPipeline(SHADER_CODE)
|
||||
me.vertices = new Float32ArrayBox()
|
||||
}
|
||||
|
||||
render(objects) {
|
||||
local commandEncoder = me.device.createCommandEncoder()
|
||||
local passEncoder = commandEncoder.beginRenderPass({
|
||||
colorAttachments: [{
|
||||
view: me.context.getCurrentTexture().createView(),
|
||||
clearValue: { r: 0, g: 0, b: 0, a: 1 },
|
||||
loadOp: "clear",
|
||||
storeOp: "store"
|
||||
}]
|
||||
})
|
||||
|
||||
passEncoder.setPipeline(me.pipeline)
|
||||
|
||||
// Nyashオブジェクトを高速描画
|
||||
loop(obj in objects) {
|
||||
me.updateVertexBuffer(obj)
|
||||
passEncoder.setVertexBuffer(0, me.vertexBuffer)
|
||||
passEncoder.draw(obj.vertexCount)
|
||||
}
|
||||
|
||||
passEncoder.end()
|
||||
me.device.queue.submit([commandEncoder.finish()])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. ブラウザ内JITコンパイル
|
||||
```javascript
|
||||
// NyashコードをWebAssemblyに動的コンパイル
|
||||
async function compileNyashToWasm(nyashCode) {
|
||||
// Tauri経由でMIR生成
|
||||
const mir = await window.__TAURI__.invoke('generate_mir', { code: nyashCode });
|
||||
|
||||
// ブラウザ内でWASMバイナリ生成
|
||||
const wasmModule = new WasmModuleBuilder()
|
||||
.addMemory(1, 100)
|
||||
.addFunction("main", kSig_i_v)
|
||||
.addBody(mirToWasmBytes(mir))
|
||||
.toModule();
|
||||
|
||||
// インスタンス化して実行
|
||||
const instance = new WebAssembly.Instance(wasmModule, {
|
||||
env: {
|
||||
print: (ptr) => console.log(readString(ptr))
|
||||
}
|
||||
});
|
||||
|
||||
return instance.exports.main();
|
||||
}
|
||||
```
|
||||
|
||||
### 📊 性能最適化戦略
|
||||
|
||||
#### 1. プリコンパイル + キャッシング
|
||||
```rust
|
||||
// Nyashアプリを事前コンパイルしてキャッシュ
|
||||
struct NyashCache {
|
||||
compiled: HashMap<String, CompiledModule>,
|
||||
}
|
||||
|
||||
impl NyashCache {
|
||||
async fn get_or_compile(&mut self, url: &str) -> Result<&CompiledModule> {
|
||||
if let Some(module) = self.compiled.get(url) {
|
||||
return Ok(module);
|
||||
}
|
||||
|
||||
// ダウンロード & コンパイル
|
||||
let code = download_nyash_code(url).await?;
|
||||
let module = compile_with_cranelift(&code)?;
|
||||
|
||||
self.compiled.insert(url.to_string(), module);
|
||||
Ok(self.compiled.get(url).unwrap())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. OffscreenCanvas + Worker
|
||||
```javascript
|
||||
// メインスレッドをブロックしない描画
|
||||
const worker = new Worker('nyash-renderer.js');
|
||||
const offscreen = canvas.transferControlToOffscreen();
|
||||
|
||||
worker.postMessage({
|
||||
cmd: 'init',
|
||||
canvas: offscreen
|
||||
}, [offscreen]);
|
||||
|
||||
// Nyashコードの実行結果をWorkerに送信
|
||||
async function runNyashInWorker(code) {
|
||||
const result = await window.__TAURI__.invoke('execute_nyash', { code });
|
||||
worker.postMessage({ cmd: 'render', data: result });
|
||||
}
|
||||
```
|
||||
|
||||
### 🎨 UI Framework統合
|
||||
|
||||
#### 1. React統合
|
||||
```jsx
|
||||
// React component that runs Nyash code
|
||||
function NyashComponent({ code, props }) {
|
||||
const [result, setResult] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
async function run() {
|
||||
const vm = await getNyashVM();
|
||||
const box = await vm.execute(code, props);
|
||||
|
||||
// Nyash BoxをReact要素に変換
|
||||
setResult(boxToReactElement(box));
|
||||
}
|
||||
run();
|
||||
}, [code, props]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 使用例
|
||||
<NyashComponent
|
||||
code={`
|
||||
box Counter {
|
||||
init { count }
|
||||
increment() { me.count++ }
|
||||
render() {
|
||||
return new DOMBox("div", {
|
||||
children: [
|
||||
new DOMBox("h1", { text: "Count: " + me.count }),
|
||||
new DOMBox("button", {
|
||||
text: "+",
|
||||
onClick: me.increment
|
||||
})
|
||||
]
|
||||
})
|
||||
}
|
||||
}
|
||||
`}
|
||||
/>
|
||||
```
|
||||
|
||||
#### 2. egui統合(Rust側)
|
||||
```rust
|
||||
// eguiでNyashアプリのUIを構築
|
||||
impl eframe::App for NyashBrowser {
|
||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
// URL入力
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("URL:");
|
||||
ui.text_edit_singleline(&mut self.url);
|
||||
if ui.button("Go").clicked() || ui.input(|i| i.key_pressed(egui::Key::Enter)) {
|
||||
self.navigate();
|
||||
}
|
||||
});
|
||||
|
||||
ui.separator();
|
||||
|
||||
// Nyashアプリの描画領域
|
||||
egui::ScrollArea::vertical().show(ui, |ui| {
|
||||
if let Some(app) = &self.current_app {
|
||||
// Nyash VMの出力をeguiウィジェットに変換
|
||||
render_nyash_output(ui, app);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 🚀 実装ロードマップ
|
||||
|
||||
1. **Week 1**: Tauri基本セットアップ
|
||||
- Tauriプロジェクト作成
|
||||
- Nyash VM統合
|
||||
- 基本的なIPC通信
|
||||
|
||||
2. **Week 2**: カスタムプロトコル
|
||||
- nyash://プロトコルハンドラー
|
||||
- .hakoファイル実行
|
||||
- 結果表示
|
||||
|
||||
3. **Week 3**: 高速化
|
||||
- JITコンパイル統合
|
||||
- キャッシングシステム
|
||||
- 共有メモリ実装
|
||||
|
||||
4. **Week 4**: UI/UX
|
||||
- egui or Web Components
|
||||
- 開発者ツール
|
||||
- ホットリロード
|
||||
|
||||
### 💡 まとめ
|
||||
|
||||
Tauri + Nyash VMの組み合わせが最も現実的で強力です:
|
||||
|
||||
1. **開発効率**: 既存のWeb技術を活用しつつネイティブ性能
|
||||
2. **配布**: 単一実行ファイルで配布可能(~10MB)
|
||||
3. **拡張性**: プラグインシステムで無限の可能性
|
||||
4. **性能**: WASM比100倍、ネイティブアプリ同等
|
||||
|
||||
「Everything is Box」の哲学により、ブラウザ自体もBoxとして扱え、エレガントな実装が可能です!
|
||||
Reference in New Issue
Block a user