Skip to content

Commit

Permalink
implement block
Browse files Browse the repository at this point in the history
  • Loading branch information
hhorikawa committed Sep 21, 2024
1 parent f49e6aa commit ea5b8c7
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 138 deletions.
69 changes: 59 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@
<a href="https://github.com/kanaka/mal/blob/master/process/guide.md">The Make-A-Lisp Process</a>
ただ, MAL は Clojure に近く、Lisp らしい感じとは若干異なる。

Common Lisp か Scheme が有力。とりあえず Common Lisp のサブセットを実装。
Common Lisp か Scheme が有力。とりあえず Common Lisp のサブセットを実装。S式の構築部分だけ, 独立して使える。

C++17
- `variant` で数値は特別扱い
- オブジェクト参照は `shared_ptr` で参照カウント方式
- リストは `vector`
- 文字列は全部 Unicode (UTF-16).



## 機能

- REPL Read-Eval-Print-Loop
+ ✅ GNU Readline はライセンスが GPLv3 なので使えない。libedit-devel を利用
+ `repl()`, `main()`
Expand All @@ -22,41 +28,84 @@ C++17
+ ✅ dotted pair notation
+ reader macro
+ Sharpsign (dispatching macro character)
- `simple-vector`
+ 複数行コメント
- `<simple-vector>`
+ ✅ 単一行コメント `;`
+ 複数行コメント `#|`...`|#`

- Environment
+ ✅ 変数定義. `SETQ`
+ ✅ レキシカルスコープ. `LET`, `LET*`
+ ✅ レキシカルスコープ. `LET`, `LET*`. `BLOCK` ではスコープ導入しない。
+ ✅ ビルトイン関数の登録

- Eval -- `EVAL()` が AST を評価.
+ ✅ 関数呼び出し. Function `FUNCALL`
- Eval -- `EVAL1()` が AST を評価.
+ ✅ 関数呼び出し.
+ ✅ atom の評価
+`lambda` 式からクロージャをつくる
+ Function `FUNCALL`. 変数を評価して, クロージャの呼び出し. Lisp-2
+ ✅ ユーザ関数の定義 `DEFUN`
+ ✅ Special operator `IF`
+ macro `DO`
+ ✅ Tail Call Optimization (TCO)

- Tail Call Optimization (TCO). 実装したがテスト未了

- Files

- ✅ Quoting `QUOTE`

- Macros
+ ✅ Backquote `quasiquote`, Comma `unquote`, `,@` `unquote-splicing`
+ ✅ Function `MACROEXPAND-1`. マクロの入れ子は未了
+ ✅ Backquote (`quasiquote`), Comma (`unquote`), `,@` (`unquote-splicing`)
+ ✅ Function `MACROEXPAND-1`.
+ マクロの入れ子
+ ✅ マクロの評価

- Try (Conditions)
+ `tagbody` & 無条件ジャンプ `go` -- 実装しない
+ `block` & `return-from` -- lexical non-local exit facility
+ `block` & `return-from` -- lexical non-local exit facility. `StopIteration` 例外を投げる
+ `catch` & `throw` -- ほかのプログラミング言語の例外処理とは異なる。実装しない
+ `handler-bind` or `handler-case` -- これが例外処理

- 構造体

- 若干のライブラリ
+ ビルトイン関数
- `<string>``<character>` の vector *にしない*.
+ type `hash-table`. `(make-hash-table)`




## Data Type Predicates の命名規則

Common Lisp は, クラス名に `-` を含まなければ `P` を, そうでなければ `-P` を末尾に付ける。そうすると, `null``atom` には `P` を付けないといかんのでは?

|CL |Scheme |type | |
|----------------|------------|--------------|--------------------------------|
| |boolean? | | Scheme のみ |
|`null` |null? |null | == (eq x '()) |
|SYMBOLP |symbol? |symbol | nil は真. |
| `atom` | |atom | NIL は真. == (not (typep x 'cons)) |
|`consp` |pair? |cons | nil は偽. == (not (typep x 'atom)) |
|`listp` |list? |list | '() は真. == (typep x '(or cons null)) |
|NUMBERP |number? |number | |
|`integerp` |integer? |integer | |
|`rationalp` | |rational | |
|`floatp` | |float | |
|`complexp` | |complex | |
|CHARACTERP |char? |character | |
|STRINGP |string? |string | |
|bit-vector-p | |bit-vector | `bit-vector` means `(vector bit)`. |
|VECTORP |vector? |vector | |
|SIMPLE-VECTOR-P | |simple-vector | |
|simple-string-p | |simple-string | |
|simple-bit-vector-p| |simple-bit-vector | |
|arrayp | |array | |
|packagep | |PACKAGE | 名前空間 |
|FUNCTIONP |procedure? |FUNCTION | マクロもクロージャも真 |
|compiled-function-p | |compiled-function | |
|STREAMP |port?, eof-object? |STREAM |Scheme: <port> を介して入出力. EOF のときは EOFオブジェクトを返す. |
|random-state-p | |RANDOM-STATE | |
|readtablep | |READTABLE | |
|hash-table-p | |HASH-TABLE | |
|pathnamep | |PATHNAME | |
| |bytevector? | | |

10 changes: 7 additions & 3 deletions environment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
#include "my_debug.h"

#include <algorithm>
#include <unicode/unistr.h>
#include <sstream>
#include <iostream>
#include <unicode/unistr.h>
#include <unicode/ustream.h>
using namespace icu;

namespace my {
Expand Down Expand Up @@ -100,9 +101,12 @@ FuncPtr Environment::find_function(const UnicodeString& symbol)
void Environment::set_value(const UnicodeString& symbol, const value_t& value,
bool constant)
{
std::cout << __func__ << ": "; PRINT(value, std::cout); std::cout << "\n"; // DEBUG
std::cout << __func__ << " at " << __LINE__ << ": ";
std::cout << symbol << " = " ;
PRINT(value, std::cout); std::cout << "\n"; // DEBUG

m_values.insert(std::make_pair(symbol, BoundValue { .val = value, .constant = constant}));
// insert() は更新しない!
m_values[symbol] = BoundValue { .val = value, .constant = constant};
}

void Environment::set_function(const UnicodeString& symbol, FuncPtr func)
Expand Down
16 changes: 16 additions & 0 deletions environment.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <map>
#include <unicode/unistr.h>
#include <functional> // std::function
#include <stack>

namespace my {

Expand Down Expand Up @@ -129,13 +130,26 @@ class Environment //: public RefCounted
// * (defun fuga (x) (+ x 10))
void set_function(const icu::UnicodeString& symbol, FuncPtr value);

void push_block_tag(const icu::UnicodeString& name) {
_block_tag.push(name);
}

// ローカルと, global environment から探す
value_t find_value(const icu::UnicodeString& symbol);

// ローカルと, global environment から探す
// @return 見つからなかったときは nullptr
FuncPtr find_function(const icu::UnicodeString& symbol);

void pop_block_tag(const icu::UnicodeString& tag) {
#ifndef NDEBUG
icu::UnicodeString t = _block_tag.top();
if (t != tag)
throw std::runtime_error("internal error");
#endif
_block_tag.pop();
}

private:
typedef std::map<icu::UnicodeString, BoundValue> ValueMap;
typedef std::map<icu::UnicodeString, FuncPtr> FuncMap;
Expand All @@ -147,6 +161,8 @@ class Environment //: public RefCounted
FuncMap m_functions; // 関数またはマクロ

EnvPtr m_outer;

std::stack<icu::UnicodeString> _block_tag;
};

extern EnvPtr globalEnv;
Expand Down
Loading

0 comments on commit ea5b8c7

Please sign in to comment.