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. 12
      example/lambda.lisp
  4. 10
      example/macro.lisp
  5. 13
      example/prog.lisp
  6. 16
      example/quote.lisp
  7. 12
      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 # 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 ```sh
$ ./lispoo example/lambda.lisp $ ./lispoo example/lambda.lisp
(6)(18) 8
18
```
$ ./lispoo example/prog.lisp > quote.lisp
(3)(2)(1)(2)(1)
```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 $ ./lispoo example/quote.lisp
("false")((+ 1 2)) false
(+ 1 2)
``` ```
[More Examples](./example)

106
core.h

@ -4,9 +4,8 @@
namespace lispoo { namespace lispoo {
inline std::shared_ptr<Expr> sum(const std::shared_ptr<List>& args) { inline std::shared_ptr<Expr> sum(const std::shared_ptr<Expr>& a,
assert_len(args, 2); const std::shared_ptr<Expr>& b) {
auto a = args->value()[0], b = args->value()[1];
if (a->type() == Type::Float if (a->type() == Type::Float
&& b->type() == Type::Float) { && b->type() == Type::Float) {
return std::make_shared<Float>(get_value<Float>(a) + get_value<Float>(b)); 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; 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 } // namespace lispoo

12
example/lambda.lisp

@ -1,6 +1,6 @@
(prog (progn
(def abc (lambda (a b c) (+ a (+ b c)))) (define abc (lambda (a b c) (+ a (+ b c))))
(set! x (abc 1 2 3)) (set! x (abc 1 2 3))
(message x) (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)))
) )

10
example/macro.lisp

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

13
example/prog.lisp

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

16
example/quote.lisp

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

12
example/sum.lisp

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

25
lispoo.cpp

@ -13,31 +13,12 @@ int main(int argc, char* argv[]) {
lispoo::oops("can't open: " + std::string(argv[1])); lispoo::oops("can't open: " + std::string(argv[1]));
} }
ss << ifs.rdbuf(); ss << ifs.rdbuf();
lispoo::init();
unsigned long cursor = 0;
std::vector<std::string> tokens; std::vector<std::string> tokens;
lispoo::tokenize(ss.str(), tokens); lispoo::tokenize(ss.str(), tokens);
unsigned long cursor = 0;
auto expr = lispoo::parse(tokens, cursor); 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); lispoo::eval(expr, lispoo::global);
return 0; return 0;
} }

74
lispoo.h

@ -77,9 +77,11 @@ private:
std::vector<std::shared_ptr<Expr>> value_; std::vector<std::shared_ptr<Expr>> value_;
}; };
class Env;
class Callable: public Expr { class Callable: public Expr {
public: 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) {} explicit Callable(Fn&& lambda) : lambda_(lambda) {}
Type type() override { return Type::Callable; } 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); auto value = get_value<List>(expr);
assert_type<Type::Symbol>(value[0]); assert_type<Type::Symbol>(value[0]);
auto name = get_value<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 // function/lambda call
// (symbol arg1 arg2 arg3 ... ) // (symbol arg1 arg2 arg3 ... )
auto callable = env->get(name); 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)) { if (!is_type<Type::Callable>(callable)) {
oops("can't call symbol: " + name); oops("can't call symbol: " + name);
} }
auto args = std::make_shared<List>(); return get_value<Callable>(callable)(expr, env);
for (auto i = 1; i < value.size(); ++i) {
args->append(eval(value[i], env));
}
return get_value<Callable>(callable)(args);
} }
} // namespace lispoo } // namespace lispoo

BIN
lispoo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Loading…
Cancel
Save