11# my.code(); Runtime API
22
3-
43## RuntimeContext (interface.ts)
54
6- 各言語のランタイムはRuntimeContextインターフェースの実装を返すフックを実装する必要があります。
7-
8- context.tsx の ` useRuntime(lang) ` は各言語のフックを呼び出し、その中で指定された言語のランタイムを返します。
9-
10- 関数はすべてuseCallbackやuseMemoなどを用いレンダリングごとに同じインスタンスを返すように実装してください。
11-
12- ### 共通
13-
14- * init?: ` () => void `
15- * useRuntime() 内のuseEffectなどで呼び出されます。ランタイムを使う側では通常呼び出す必要はないです。
16- * ランタイムの初期化にコストがかかるものは、init()で初期化フラグがトリガーされたときだけ初期化するようにします。
17- * useRuntime() が複数回使われた場合はinitも複数回呼ばれます。
18- * init()はフラグを立てるだけにし、完了する前にreturnしてよいです。初期化とcleanupはuseEffect()で非同期に行うのがよいと思います。
19- * ready: ` boolean `
20- * ランタイムの初期化が完了したか、不要である場合true
21- * mutex?: ` MutexInterface `
22- * ランタイムに排他制御が必要な場合、MutexInterfaceのインスタンスを返してください。
23- * interrupt?: ` () => void `
24- * 実行中のコマンドを中断します。
25- * 呼び出し側でmutexのロックはしません。interrupt()を呼ぶ際にはrunCommand()やrunFiles()が実行中であるためmutexはすでにロックされているはずです。
26- * interrupt()内で実行中の処理のPromiseをrejectしたあと、runtimeを再開する際の処理に必要であればmutexをロックすることも可能です。
27-
28- ### REPL用
29-
30- * runCommand?: ` (command: string) => Promise<ReplOutput[]> `
31- * コマンドを実行します。実行結果をReplOutputの配列で返します。
32- * runCommandを呼び出す際には呼び出し側 (主に repl.tsx) でmutexをロックします。複数のコマンドを連続実行したい場合があるからです。
33- * checkSyntax?: ` (code: string) => Promise<SyntaxStatus> `
34- * コードの構文チェックを行います。行がコマンドとして完結していれば` complete ` 、次の行に続く場合(if文の条件式の途中など)は` incomplete ` を返してください。
35- * REPLでEnterを押した際の動作に影響します。
36- * 呼び出し側でmutexのロックはせず、必要であればcheckSyntax()内でロックします。
37- * splitReplExamples?: ` (code: string) => ReplCommands[] `
38- * markdown内に記述されているREPLのサンプルコードをパースします。例えば
39- ```
40- >>> if True:
41- ... print("Hello")
42- Hello
43- ```
44- をsplitReplExamplesに通すと
45- ```ts
46- [
47- {
48- command: 'if True:\n print("Hello")',
49- output: {
50- type: 'output',
51- content: 'Hello'
52- }
53- }
54- ]
55- ```
56- が返されるようにします。
57-
58- ### ファイル実行用
59-
60- * runFiles: `(filenames: string[], files: Record<string, string>) => Promise<ReplOutput[]>`
61- * 指定されたファイルを実行します。
62- * EmbedContextから取得したfilesを呼び出し側で引数に渡します
63- * 呼び出し側でmutexのロックはせず、必要であればrunFiles()内でロックします。
64- * getCommandlineStr: `(filenames: string[]) => string`
65- * 指定されたファイルを実行するためのコマンドライン引数文字列を返します。表示用です。
66-
67- ## languages.ts
68-
69- ### LangConstant
70-
71- 言語ごとに固定の定数です。
72-
73- * tabSize: `number`
74- * REPLおよびコードエディターののタブ幅を指定します。1以上
75- * prompt?: `string`
76- * REPLの1行目のプロンプト文字列を指定します。
77- * promptMore?: `string`
78- * REPLの2行目以降のプロンプト文字列を指定します。省略時はpromptが使われます
79-
80- ## embedContext.tsx
81-
82- Replの実行結果(`replOutputs`)、ユーザーが編集したファイル(`files`)、ファイルの実行結果(`execResults`)の情報を保持します。
83-
84- ## terminal.tsx
85-
86- xterm.jsを制御する useTerminal() フックを提供します。
87- リサイズやテーマ切り替えなどの処理を行います。
88-
89- 引数:
90- * getRows?: `(cols: number) => number`
91- * ターミナルの幅がcolsの場合の高さの最小値を指定します。
92- * 未指定または5未満の場合5になります。
93- * 内部でuseRefを使用しターミナル初期化完了の瞬間のgetRows関数インスタンスが呼び出されるので、一時オブジェクトでも大丈夫
94- * onReady?: `() => void`
95- * ターミナルが初期化された際に呼び出されます。
96- * 内部でuseRefを使用しターミナル初期化完了の瞬間のonReady関数インスタンスが呼び出されるので、一時オブジェクトでも大丈夫
97-
98- 返り値:
99- * terminalRef: `RefObject<HTMLDivElement>`
100- * ターミナルを描画するためのdiv要素にこのrefを渡してください。
101- * terminalInstanceRef: `RefObject<Terminal | null>`
102- * xterm.jsのTerminalインスタンスへのrefです。
103- * termReady: `boolean`
104- * ターミナルが初期化されたかどうかを示します。
5+ 各言語の実行環境は` RuntimeContext ` インターフェースの実装を返すフックを実装する必要があります。
1056
106- ## repl .tsx
7+ ## context .tsx
1078
108- ReplTerminal コンポーネントを提供します。
109- useRuntimeとuseTerminalを呼び出し、REPLの入出力、キーハンドリング処理を行います。
9+ * RuntimeProvider がすべての言語の実行環境のコンテキストを管理します。
10+ * useRuntime() で使用したい言語のコンテキストを取得します。
11+ * useRuntimeAll() ですべての言語のコンテキストを取得します。ただしinit()は自動的に呼び出されません
11012
111- また、実行したコマンド結果はEmbedContextに送信されます。
112-
113- シンタックスハイライトはprism.jsでパースしたものを独自処理で色付けしています。(highlight.ts 内の highlightCodeToAnsi 関数)
114- パース処理の実装は不要ですがhighlight.tsに言語定義のインポートとswitch文分岐の追加が必要です。
115-
116- ## editor.tsx
117-
118- EditorComponent コンポーネントを提供します。
119-
120- ファイルの内容はEmbedContextと同期されます。
121-
122- ## exec.tsx
123-
124- 実行ボタンと結果を表示する ExecFile コンポーネントを提供します。
125-
126- 実行結果はEmbedContextに送信されます。
13+ ## languages.ts
12714
128- ## page.tsx, tests.ts
15+ * markdownで指定される可能性のある言語名をすべて列挙します。
16+ * ReactAce, ReactSyntaxHighlighter, Prism.js における言語名との対応関係を定義します。
17+ * ReactAceで利用可能な言語の場合tab幅も指定します。
18+ * REPL実行環境が利用可能な言語の場合プロンプト文字列などのパラメータを指定します。
12919
130- ブラウザーで localhost:3000/terminal を開くと、各実行環境のテストを行います。
20+ ## tests
13121
132- ランタイムを追加した場合、ここにテストケースを追加してください。
22+ * ` npm run test -w packages/runtime ` でvitestを使ってテストを実行できます
23+ * my.code(); の /terminal ページでMochaを使ってテストを実行できます
24+ * どちらからでも実行できるようテスト本体は ./tests/repl.ts, ./tests/fileExecution.ts に記述しています。
25+ 新しい言語の実行環境を追加した場合、ここにテストケースを追加してください。
13326
13427## 各言語の実装
13528
@@ -138,24 +31,26 @@ EditorComponent コンポーネントを提供します。
13831web worker でコードを実行する実装です。
13932workerとの通信部分は言語によらず共通なので、それをworker/runtime.tsxで定義しています。
14033
141- Pythonの実行環境にはPyodideを使用しています。
142- PyodideにはKeyboardInterruptを送信する機能があるのでinterrupt()でそれを利用しています。
143-
144- Rubyの実行環境にはruby.wasmを使用しています。
145-
146- JavaScriptはeval()を使用しています。
34+ * Python (Pyodide)
35+ * PyodideにはKeyboardInterruptを送信する機能があるのでinterrupt()でそれを利用しています。
36+ * next.config.tsで指定しているwebpackのPyodidePluginにより、pyodide本体は ` /_next/static/pyodide/バージョン/ ` 以下に出力され、それをimportします。
37+ * ただしvitest時には利用できないのでCDNにフォールバックしています
38+ * Ruby (ruby.wasm)
39+ * JavaScript (eval)
40+ * 実装は複雑になるので別パッケージ (packages/jsEval) に分離し、独立したテストもそちらに記述しています
14741
14842### Wandbox
14943
15044wandbox.org のAPIを利用してコードを実行します。
15145
15246APIから利用可能なコンパイラとオプションのリストが得られるので、言語ごとにそこからオプションを選択するロジックを実装しています。
15347
154- C++ではg++の中でheadでない最新のものを選択し、warningスイッチオン、boost有効、std=最新を指定しています。
155- また、コード実行時にシグナルハンドラーをユーザーのコードに挿入し、エラー時にスタックトレースを表示する処理とそれをjs側でパースする処理を実装しています。
156-
157- Rustは最新のものを選択し、-Cdebuginfo=1を追加しています。
158- ユーザーのコードをモジュールとしてprog.rsのmain()から呼び出す形に変更しており、ユーザーのコードに `mod foo;` → `use super::foo;`, `fn main()` → `pub fn main()` の改変を加えています。
48+ * C++
49+ * g++の中でheadでない最新のものを選択し、warningスイッチオン、boost有効、std=最新を指定しています。
50+ * また、コード実行時にシグナルハンドラーをユーザーのコードに挿入し、エラー時にスタックトレースを表示する処理とそれをjs側でパースする処理を実装しています。
51+ * Rust
52+ * 最新のrustcを選択し、-Cdebuginfo=1を追加しています。
53+ * ユーザーのコードをモジュールとしてprog.rsのmain()から呼び出す形に変更しており、ユーザーのコードに ` mod foo; ` → ` use super::foo; ` , ` fn main() ` → ` pub fn main() ` の改変を加えています。
15954
16055### TypeScript
16156
0 commit comments