Files
hakorune/docs/archive/design/lisp_interpreter_design.md

300 lines
7.5 KiB
Markdown
Raw Permalink 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 LISP インタープリタ設計書
## 概要
Nyash上で動作するLISPインタープリタを実装する。「Everything is Box」哲学に基づき、LISPのS式をNyashのBoxで表現する。
## 🏗️ アーキテクチャ
### 1. コアBox実装
#### ConsBox - cons cellペア
```nyash
box ConsBox {
car // 最初の要素
cdr // 残りの要素通常は別のConsBoxかNullBox
init { car, cdr }
func getCar() { return me.car }
func getCdr() { return me.cdr }
func setCar(value) { me.car = value }
func setCdr(value) { me.cdr = value }
func toString() {
if (NullBox.isNull(me.cdr)) {
return "(" + me.car.toString() + ")"
}
// TODO: 適切なリスト表示
return "(" + me.car.toString() + " . " + me.cdr.toString() + ")"
}
}
```
#### SymbolBox - シンボル
```nyash
box SymbolBox {
name
init { name }
func getName() { return me.name }
func toString() { return me.name }
}
```
#### LispEnvironment - 変数環境
```nyash
box LispEnvironment {
bindings // MapBox: symbol name -> value
parent // 親環境(スコープチェーン用)
init { parent }
func define(symbol, value) {
me.bindings.set(symbol.getName(), value)
}
func lookup(symbol) {
name = symbol.getName()
if (me.bindings.has(name)) {
return me.bindings.get(name)
}
if (not NullBox.isNull(me.parent)) {
return me.parent.lookup(symbol)
}
return new ErrorBox("Unbound variable: " + name)
}
}
```
### 2. S式パーサー
```nyash
box SExpressionParser {
tokens
position
init { input }
func parse() {
me.tokens = me.tokenize(input)
me.position = 0
return me.parseExpression()
}
func parseExpression() {
token = me.currentToken()
if (token == "(") {
return me.parseList()
}
if (token.isNumber()) {
return new IntegerBox(token.toNumber())
}
if (token.isString()) {
return new StringBox(token.getValue())
}
// シンボル
return new SymbolBox(token)
}
func parseList() {
me.consume("(")
elements = new ArrayBox()
loop(me.currentToken() != ")") {
elements.push(me.parseExpression())
}
me.consume(")")
return me.arrayToConsList(elements)
}
}
```
### 3. eval関数
```nyash
box LispEvaluator {
globalEnv
init {}
func eval(expr, env) {
// 自己評価的な値
if (expr.isNumber() or expr.isString()) {
return expr
}
// シンボル
if (expr.isSymbol()) {
return env.lookup(expr)
}
// リスト(関数適用か特殊形式)
if (expr.isCons()) {
car = expr.getCar()
// 特殊形式のチェック
if (car.isSymbol()) {
name = car.getName()
if (name == "quote") {
return me.evalQuote(expr, env)
}
if (name == "if") {
return me.evalIf(expr, env)
}
if (name == "define") {
return me.evalDefine(expr, env)
}
if (name == "lambda") {
return me.evalLambda(expr, env)
}
// ... 他の特殊形式
}
// 通常の関数適用
func = me.eval(car, env)
args = me.evalList(expr.getCdr(), env)
return me.apply(func, args)
}
return expr
}
func apply(func, args) {
// プリミティブ関数
if (func.isPrimitive()) {
return func.applyPrimitive(args)
}
// ラムダ式
if (func.isLambda()) {
newEnv = new LispEnvironment(func.getEnv())
params = func.getParams()
// パラメータをバインド
// ... 実装
return me.eval(func.getBody(), newEnv)
}
return new ErrorBox("Not a function: " + func.toString())
}
}
```
### 4. 基本関数の実装
```nyash
box LispPrimitives {
func setupGlobalEnv(env) {
// 算術演算
env.define(new SymbolBox("+"), new PrimitiveBox(me.add))
env.define(new SymbolBox("-"), new PrimitiveBox(me.subtract))
env.define(new SymbolBox("*"), new PrimitiveBox(me.multiply))
env.define(new SymbolBox("/"), new PrimitiveBox(me.divide))
// リスト操作
env.define(new SymbolBox("cons"), new PrimitiveBox(me.cons))
env.define(new SymbolBox("car"), new PrimitiveBox(me.car))
env.define(new SymbolBox("cdr"), new PrimitiveBox(me.cdr))
env.define(new SymbolBox("list"), new PrimitiveBox(me.list))
// 述語
env.define(new SymbolBox("null?"), new PrimitiveBox(me.isNull))
env.define(new SymbolBox("pair?"), new PrimitiveBox(me.isPair))
env.define(new SymbolBox("number?"), new PrimitiveBox(me.isNumber))
// 比較
env.define(new SymbolBox("="), new PrimitiveBox(me.equal))
env.define(new SymbolBox("<"), new PrimitiveBox(me.lessThan))
env.define(new SymbolBox(">"), new PrimitiveBox(me.greaterThan))
}
func add(args) {
sum = 0
current = args
loop(not NullBox.isNull(current)) {
sum = sum + current.getCar().getValue()
current = current.getCdr()
}
return new IntegerBox(sum)
}
// ... 他のプリミティブ関数
}
```
## 🎮 使用例
```lisp
; Nyash LISPでの階乗計算
(define factorial
(lambda (n)
(if (= n 0)
1
(* n (factorial (- n 1))))))
(factorial 5) ; => 120
; リスト操作
(define map
(lambda (f lst)
(if (null? lst)
'()
(cons (f (car lst))
(map f (cdr lst))))))
(map (lambda (x) (* x x)) '(1 2 3 4 5)) ; => (1 4 9 16 25)
```
## 📋 実装ステップ
1. **Phase 1: 基本データ構造**
- ConsBox実装
- SymbolBox実装
- 基本的なリスト操作
2. **Phase 2: パーサー**
- トークナイザー
- S式パーサー
- 文字列→Box変換
3. **Phase 3: 評価器**
- eval関数の基本実装
- 環境Environment管理
- 特殊形式の処理
4. **Phase 4: 基本関数**
- 四則演算
- リスト操作cons, car, cdr
- 述語関数
5. **Phase 5: 高度な機能**
- lambda式
- クロージャ
- 再帰関数のサポート
6. **Phase 6: 最適化とデバッグ**
- DebugBoxとの統合
- エラーハンドリングの改善
- パフォーマンス最適化
## 🎯 成功基準
- 基本的なLISPプログラムが動作する
- 再帰関数が正しく実行される
- リスト操作が適切に機能する
- Nyashの他のBox機能と統合できる
## 💡 技術的課題
1. **末尾再帰最適化**: NyashはTCOをサポートしていないため、深い再帰でスタックオーバーフローの可能性
2. **ガベージコレクション**: Nyashのfini()との統合方法
3. **マクロシステム**: 将来的な実装検討事項
---
「Everything is Box」の究極の実証 - LISPインタープリタ on Nyash