Browse Source

unify synatx and normal function impl

Signed-off-by: Rain Mark <rain.by.zhou@gmail.com>
main
Rain Mark 4 years ago
parent
commit
6222908852
  1. 35
      README.md
  2. 106
      core.h
  3. 6
      example/lambda.lisp
  4. 4
      example/macro.lisp
  5. 9
      example/prog.lisp
  6. 4
      example/quote.lisp
  7. 2
      example/sum.lisp
  8. 25
      lispoo.cpp
  9. 74
      lispoo.h
  10. BIN
      lispoo.png

35
README.md

@ -10,15 +10,40 @@ $ ./build.sh
# example
![lispoo.png](./lispoo.png)
> lambda.lisp
```lisp
(progn
(define abc (lambda (a b c) (+ a (+ b c))))
(set! x (abc 1 2 3))
(message x)
(progn (+ 1.2 3.9) (define plus (lambda (a b) (+ a b))) (message (plus 9 9)))
)
```
```sh
$ ./lispoo example/lambda.lisp
(6)(18)
8
18
```
$ ./lispoo example/prog.lisp
(3)(2)(1)(2)(1)
> quote.lisp
```lisp
(progn
(define test (lambda (x) x))
(if (test (quote (+ 1 -1)))
(message (quote true))
(message (quote false))
)
(message (quote (+ 1 2)))
)
```
```sh
$ ./lispoo example/quote.lisp
("false")((+ 1 2))
false
(+ 1 2)
```
[More Examples](./example)

106
core.h

@ -4,9 +4,8 @@
namespace lispoo {
inline std::shared_ptr<Expr> sum(const std::shared_ptr<List>& args) {
assert_len(args, 2);
auto a = args->value()[0], b = args->value()[1];
inline std::shared_ptr<Expr> sum(const std::shared_ptr<Expr>& a,
const std::shared_ptr<Expr>& b) {
if (a->type() == Type::Float
&& b->type() == Type::Float) {
return std::make_shared<Float>(get_value<Float>(a) + get_value<Float>(b));
@ -64,4 +63,105 @@ inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) {
return nil;
}
inline void init() {
// syntax
putenv("quote",
[](auto expr, auto env) {
assert_len(expr, 2);
auto value = get_value<List>(expr);
return value[1];
});
putenv("define",
[](auto expr, auto env) {
assert_len(expr, 3);
auto value = get_value<List>(expr);
assert_type<Type::Symbol>(value[1]);
auto symbol = get_value<Symbol>(value[1]);
if (!is_nil(env->get(symbol))) {
oops("symbol defined: " + symbol);
}
env->put(symbol, eval(value[2], env));
return nil;
});
putenv("set!",
[](auto expr, auto env) {
assert_len(expr, 3);
auto value = get_value<List>(expr);
assert_type<Type::Symbol>(value[1]);
auto symbol = get_value<Symbol>(value[1]);
env->put(symbol, eval(value[2], env));
return nil;
});
putenv("progn",
[](auto expr, auto env) {
auto val = nil;
auto value = get_value<List>(expr);
for (auto i = 1; i < value.size(); ++i) {
val = eval(value[i], env);
}
return val;
});
putenv("if",
[](auto expr, auto env) {
// (if (cond) (then body) (else body))
assert_len(expr, 4);
auto value = get_value<List>(expr);
if (is_true(eval(value[1], env))) {
return eval(value[2], env);
} else {
return eval(value[3], env);
}
});
putenv("while",
[](auto expr, auto env) {
// (while (cond) (loop body))
assert_len(expr, 3);
auto value = get_value<List>(expr);
while (is_true(eval(value[1], env))) {
eval(value[2], env);
}
return nil;
});
putenv("lambda",
[](auto expr, auto env) {
// (lambda (args) (body))
assert_len(expr, 3);
auto lambda =
[expr, parent = env](auto args, auto) {
auto value = get_value<List>(expr);
auto symbols = get_value<List>(value[1]);
// arguments bind
auto args_value = get_value<List>(args);
if (symbols.size() != args_value.size() - 1) {
oops("arguments error");
}
auto env = std::make_shared<Env>(parent);
for (auto i = 0; i < symbols.size(); ++i) {
auto symbol = get_value<Symbol>(symbols[i]);
env->put(symbol, eval(args_value[i + 1], parent));
}
// eval body
return eval(value[2], env);
};
return std::make_shared<Callable>(std::move(lambda));
});
// normal builtin function
putenv("+",
[](auto expr, auto env) {
assert_len(expr, 3);
auto value = get_value<List>(expr);
return sum(eval(value[1], env), eval(value[2], env));
});
putenv("message",
[](auto expr, auto env) {
auto value = get_value<List>(expr);
for (auto i = 1; i < value.size(); ++i) {
message(eval(value[i], env));
std::cout << std::endl;
}
return nil;
});
}
} // namespace lispoo

6
example/lambda.lisp

@ -1,6 +1,6 @@
(prog
(def abc (lambda (a b c) (+ a (+ b c))))
(progn
(define abc (lambda (a b c) (+ a (+ b c))))
(set! x (abc 1 2 3))
(message x)
(prog (+ 1.2 3.9) (def plus (lambda (a b) (+ a b))) (message (plus 9 9)))
(progn (+ 1.2 3.9) (define plus (lambda (a b) (+ a b))) (message (plus 9 9)))
)

4
example/macro.lisp

@ -1,5 +1,5 @@
(prog
(progn
(message (quote (name args)))
(def echo message)
(define echo message)
(echo 1)
)

9
example/prog.lisp

@ -1,6 +1,7 @@
(prog
(progn
(set! i 3)
(while i (prog (message i) (set! i (+ i -1))))
(prog (set! x 0) (message (if x 1 2)))
(prog (set! x 1) (message x))
(while i (progn (message i) (set! i (+ i -1))))
(progn (set! x 0) (message (if x 1 2)))
(progn (set! x 1) (message x))
(message (progn (+ 1 1) (+ 2 2)))
)

4
example/quote.lisp

@ -1,5 +1,5 @@
(prog
(def test (lambda (x) x))
(progn
(define test (lambda (x) x))
(if (test (quote (+ 1 -1)))
(message (quote true))
(message (quote false))

2
example/sum.lisp

@ -1,4 +1,4 @@
(prog
(progn
(message (+
(+ 2 1.1)
1))

25
lispoo.cpp

@ -13,31 +13,12 @@ int main(int argc, char* argv[]) {
lispoo::oops("can't open: " + std::string(argv[1]));
}
ss << ifs.rdbuf();
lispoo::init();
unsigned long cursor = 0;
std::vector<std::string> tokens;
lispoo::tokenize(ss.str(), tokens);
unsigned long cursor = 0;
auto expr = lispoo::parse(tokens, cursor);
lispoo::putenv("+", [](auto args) {
return lispoo::sum(args);
});
lispoo::putenv("car", [](auto args) {
return args->value()[0];
});
lispoo::putenv("cdr", [](auto args) {
auto value = args->value();
auto cdr = std::make_shared<lispoo::List>();
cdr->value().assign(value.begin() + 1, value.end());
return cdr;
});
lispoo::putenv("message", [](auto args) {
auto value = lispoo::get_value<lispoo::List>(args);
for (auto& v : value) {
lispoo::message(v);
std::cout << std::endl;
}
return lispoo::nil;
});
lispoo::eval(expr, lispoo::global);
return 0;
}

74
lispoo.h

@ -77,9 +77,11 @@ private:
std::vector<std::shared_ptr<Expr>> value_;
};
class Env;
class Callable: public Expr {
public:
using Fn = std::function<std::shared_ptr<Expr>(const std::shared_ptr<List>&)>;
using Fn = std::function<std::shared_ptr<Expr>(const std::shared_ptr<Expr>&,
const std::shared_ptr<Env>& env)>;
explicit Callable(Fn&& lambda) : lambda_(lambda) {}
Type type() override { return Type::Callable; }
@ -248,70 +250,6 @@ inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::
auto value = get_value<List>(expr);
assert_type<Type::Symbol>(value[0]);
auto name = get_value<Symbol>(value[0]);
if (name == "quote") {
assert_len(expr, 2);
return value[1];
}
if (name == "def") {
assert_len(expr, 3);
assert_type<Type::Symbol>(value[1]);
auto symbol = get_value<Symbol>(value[1]);
if (!is_nil(env->get(symbol))) {
oops("symbol defined: " + symbol);
}
env->put(symbol, eval(value[2], env));
return nil;
}
if (name == "set!") {
assert_len(expr, 3);
assert_type<Type::Symbol>(value[1]);
auto symbol = get_value<Symbol>(value[1]);
env->put(symbol, eval(value[2], env));
return nil;
}
if (name == "prog") {
for (auto i = 1; i < value.size(); ++i) {
eval(value[i], env);
}
return nil;
}
if (name == "if") {
// (if (cond) (then body) (else body))
assert_len(expr, 4);
if (is_true(eval(value[1], env))) {
return eval(value[2], env);
} else {
return eval(value[3], env);
}
}
if (name == "while") {
// (while (cond) (loop body))
assert_len(expr, 3);
while (is_true(eval(value[1], env))) {
eval(value[2], env);
}
return nil;
}
if (name == "lambda") {
// (lambda (args) (body))
assert_len(expr, 3);
auto lambda = [expr, parent = env](const std::shared_ptr<List>& args) {
auto value = get_value<List>(expr);
auto symbols = get_value<List>(value[1]);
// arguments bind
if (symbols.size() != args->value().size()) {
oops("arguments error");
}
auto env = std::make_shared<Env>(parent);
for (auto i = 0; i < symbols.size(); ++i) {
auto symbol = get_value<Symbol>(symbols[i]);
env->put(symbol, args->value()[i]);
}
// eval body
return eval(value[2], env);
};
return std::make_shared<Callable>(std::move(lambda));
}
// function/lambda call
// (symbol arg1 arg2 arg3 ... )
auto callable = env->get(name);
@ -321,11 +259,7 @@ inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::
if (!is_type<Type::Callable>(callable)) {
oops("can't call symbol: " + name);
}
auto args = std::make_shared<List>();
for (auto i = 1; i < value.size(); ++i) {
args->append(eval(value[i], env));
}
return get_value<Callable>(callable)(args);
return get_value<Callable>(callable)(expr, env);
}
} // namespace lispoo

BIN
lispoo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Loading…
Cancel
Save