Browse Source

add some utils func

Signed-off-by: Rain Mark <rain.by.zhou@gmail.com>
main
Rain Mark 4 years ago
parent
commit
4b400d6146
  1. 30
      core.h
  2. 5
      example/macro.lisp
  3. 4
      example/quote.lisp
  4. 24
      lispoo.cpp
  5. 163
      lispoo.h

30
core.h

@ -5,32 +5,26 @@
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<List>& args) {
len_eq(args, 2); assert_len(args, 2);
auto a = args->value()[0], b = args->value()[1]; 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>(std::static_pointer_cast<Float>(a)->value() + return std::make_shared<Float>(get_value<Float>(a) + get_value<Float>(b));
std::static_pointer_cast<Float>(b)->value());
} }
if (a->type() == Type::Integer if (a->type() == Type::Integer
&& b->type() == Type::Integer) { && b->type() == Type::Integer) {
return std::make_shared<Integer>(std::static_pointer_cast<Integer>(a)->value() + return std::make_shared<Integer>(get_value<Integer>(a) + get_value<Integer>(b));
std::static_pointer_cast<Integer>(b)->value());
} }
if (a->type() == Type::Float) { if (a->type() == Type::Float) {
return std::make_shared<Float>(std::static_pointer_cast<Float>(a)->value() + return std::make_shared<Float>(get_value<Float>(a) + get_value<Integer>(b));
std::static_pointer_cast<Integer>(b)->value());
} }
if (b->type() == Type::Float) { if (b->type() == Type::Float) {
return std::make_shared<Float>(std::static_pointer_cast<Integer>(a)->value() + return std::make_shared<Float>(get_value<Integer>(a) + get_value<Float>(b));
std::static_pointer_cast<Float>(b)->value());
} }
return nil;
} }
inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) { inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) {
if (!expr) {
return null_expr;
}
auto type = expr->type(); auto type = expr->type();
switch (type) { switch (type) {
case Type::Null: { case Type::Null: {
@ -38,23 +32,23 @@ inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) {
break; break;
} }
case Type::Integer: { case Type::Integer: {
std::cout << std::static_pointer_cast<Integer>(expr)->value(); std::cout << get_value<Integer>(expr);
break; break;
} }
case Type::Float: { case Type::Float: {
std::cout << std::static_pointer_cast<Float>(expr)->value(); std::cout << get_value<Float>(expr);
break; break;
} }
case Type::Symbol: { case Type::Symbol: {
std::cout << std::static_pointer_cast<Symbol>(expr)->value(); std::cout << get_value<Symbol>(expr);
break; break;
} }
case Type::Callable: { case Type::Callable: {
std::cout << "<function>: " << expr.get(); std::cout << "<fn>: " << expr.get();
break; break;
} }
case Type::List: { case Type::List: {
auto& value = std::static_pointer_cast<List>(expr)->value(); auto value = get_value<List>(expr);
std::cout << "("; std::cout << "(";
for (auto i = 0; i < value.size(); ++i) { for (auto i = 0; i < value.size(); ++i) {
if (i > 0) { if (i > 0) {
@ -67,7 +61,7 @@ inline std::shared_ptr<Expr> message(const std::shared_ptr<Expr>& expr) {
default: default:
break; break;
} }
return null_expr; return nil;
} }
} // namespace lispoo } // namespace lispoo

5
example/macro.lisp

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

4
example/quote.lisp

@ -1,8 +1,8 @@
(prog (prog
(def test (lambda (x) x)) (def 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)))
) )

24
lispoo.cpp

@ -5,7 +5,7 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
if (argc != 2) { if (argc != 2) {
lispoo::oops("lispoo ./xxx.lisp"); lispoo::oops("error: no input files");
} }
std::ifstream ifs(argv[1]); std::ifstream ifs(argv[1]);
std::stringstream ss; std::stringstream ss;
@ -18,8 +18,26 @@ int main(int argc, char* argv[]) {
unsigned long cursor = 0; unsigned long cursor = 0;
auto expr = lispoo::parse(tokens, cursor); auto expr = lispoo::parse(tokens, cursor);
lispoo::register_symbol("+", [](auto args) { return lispoo::sum(args); }); lispoo::putenv("+", [](auto args) {
lispoo::register_symbol("message", [](auto args) { return lispoo::message(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;
} }

163
lispoo.h

@ -13,7 +13,7 @@ namespace lispoo {
inline void oops(const std::string& err) { inline void oops(const std::string& err) {
std::cerr << err << std::endl; std::cerr << err << std::endl;
exit(-1); std::exit(EXIT_FAILURE);
} }
enum class Type { enum class Type {
@ -65,12 +65,12 @@ class Null: public Expr {
public: public:
Type type() override { return Type::Null; } Type type() override { return Type::Null; }
}; };
static const std::shared_ptr<Null> null_expr = std::make_shared<Null>(); static const std::shared_ptr<Expr> nil = std::make_shared<Null>();
class List: public Expr { class List: public Expr {
public: public:
Type type() override { return Type::List; } Type type() override { return Type::List; }
const std::vector<std::shared_ptr<Expr>>& value() const { return value_; } std::vector<std::shared_ptr<Expr>>& value() { return value_; }
void append(const std::shared_ptr<Expr>& expr) { value_.emplace_back(expr); } void append(const std::shared_ptr<Expr>& expr) { value_.emplace_back(expr); }
private: private:
@ -91,66 +91,87 @@ private:
Fn lambda_; Fn lambda_;
}; };
// environment
class Env { class Env {
public: public:
Env(const std::shared_ptr<Env>& env) : env_(env) {} Env(const std::shared_ptr<Env>& env) : env_(env) {}
std::shared_ptr<Expr> get(const std::shared_ptr<Symbol>& symbol) const { std::shared_ptr<Expr> get(const std::string& symbol) const {
// std::cout << "get: " << symbol->value() << std::endl; auto it = expr_map_.find(symbol);
auto it = expr_map_.find(symbol->value());
if (it != expr_map_.end()) { if (it != expr_map_.end()) {
return it->second; return it->second;
} }
if (env_) { if (env_) {
return env_->get(symbol); return env_->get(symbol);
} }
return null_expr; return nil;
} }
void put(const std::shared_ptr<Symbol>& symbol, const std::shared_ptr<Expr>& expr) { void put(const std::string& symbol, const std::shared_ptr<Expr>& expr) {
// std::cout << "put: " << symbol->value() << std::endl; expr_map_[symbol] = expr;
expr_map_[symbol->value()] = expr;
} }
private: private:
std::unordered_map<std::string, std::shared_ptr<Expr>> expr_map_; std::unordered_map<std::string, std::shared_ptr<Expr>> expr_map_;
std::shared_ptr<Env> env_; std::shared_ptr<Env> env_;
}; };
static std::shared_ptr<Env> global = std::make_shared<Env>(std::shared_ptr<Env>()); static std::shared_ptr<Env> global = std::make_shared<Env>(std::shared_ptr<Env>());
inline void putenv(const std::string& symbol, Callable::Fn&& lambda) {
inline void register_symbol(const std::string& symbol, Callable::Fn&& lambda) { global->put(symbol, std::make_shared<Callable>(std::forward<Callable::Fn>(lambda)));
global->put(std::make_shared<Symbol>(symbol), std::make_shared<Callable>(std::forward<Callable::Fn>(lambda)));
} }
// type utils
inline bool is_par(char ch) { inline bool is_par(char ch) {
return ch == '(' || ch == ')'; return ch == '(' || ch == ')';
} }
inline bool is_number(const Type& type) { template <typename T>
return type == Type::Integer || type == Type::Float; inline decltype(auto) get_value(const std::shared_ptr<Expr>& expr) {
return std::static_pointer_cast<T>(expr)->value();
} }
inline bool is_atom(const Type& type) { template <Type t>
return type < Type::Atom; inline bool is_type(const std::shared_ptr<Expr>& expr) {
return expr && expr->type() == t;
}
inline bool is_nil(const std::shared_ptr<Expr>& expr) {
return is_type<Type::Null>(expr);
}
inline bool is_number(const std::shared_ptr<Expr>& expr) {
return is_type<Type::Integer>(expr) || is_type<Type::Float>(expr);
}
inline bool is_symbol(const std::shared_ptr<Expr>& expr) {
return is_type<Type::Symbol>(expr);
} }
inline bool is_true(const std::shared_ptr<Expr>& expr) { inline bool is_true(const std::shared_ptr<Expr>& expr) {
if (!is_number(expr->type())) { if (!is_number(expr)) {
return false; return false;
} }
if (expr->type() == Type::Integer) { if (is_type<Type::Integer>(expr)) {
return std::static_pointer_cast<Integer>(expr)->value(); return get_value<Integer>(expr);
} }
return std::static_pointer_cast<Float>(expr)->value() != 0.0; return get_value<Float>(expr);
} }
inline void len_eq(const std::shared_ptr<Expr>& expr, unsigned long expect) {
if (expr->type() != Type::List) { // asserts
oops("len_eq() can't check non List type");
template <Type t>
inline void assert_type(const std::shared_ptr<Expr>& expr) {
if (!is_type<t>(expr)) {
oops("syntax error");
}
}
inline void assert_len(const std::shared_ptr<Expr>& expr, unsigned long expect) {
if (!is_type<Type::List>(expr)) {
oops("assert_len() failed, not List type");
} }
auto list = std::static_pointer_cast<List>(expr); auto value = get_value<List>(expr);
if (list->value().size() != expect) { if (value.size() != expect) {
auto symbol = std::static_pointer_cast<Symbol>(list->value()[0]); oops("assert_len() failed, expect: " + std::to_string(expect));
oops("symbol: " + symbol->value() + " length not eq: " + std::to_string(expect));
} }
} }
// parse & evaluate
inline void tokenize(const std::string& str, std::vector<std::string>& tokens) { inline void tokenize(const std::string& str, std::vector<std::string>& tokens) {
for (auto i = 0; i < str.size(); ++i) { for (auto i = 0; i < str.size(); ++i) {
if (std::isspace(str[i])) { if (std::isspace(str[i])) {
@ -186,21 +207,22 @@ inline std::shared_ptr<Expr> parse_atom(const std::vector<std::string>& tokens,
} }
} }
switch (type) { switch (type) {
case Type::Symbol: case Type::Symbol:
return std::make_shared<Symbol>(token); return std::make_shared<Symbol>(token);
case Type::Integer: case Type::Integer:
return std::make_shared<Integer>(std::stol(token)); return std::make_shared<Integer>(std::stol(token));
case Type::Float: case Type::Float:
return std::make_shared<Float>(std::stod(token)); return std::make_shared<Float>(std::stod(token));
default:
break;
} }
return std::shared_ptr<Expr>(); return nil;
} }
inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, unsigned long& cursor) { inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, unsigned long& cursor) {
if (cursor >= tokens.size()) { if (cursor >= tokens.size()) {
oops("parse error"); oops("parse error");
} }
// std::cout << "parse: " << tokens[cursor] << std::endl;
if (tokens[cursor] == "(") { if (tokens[cursor] == "(") {
auto list = std::make_shared<List>(); auto list = std::make_shared<List>();
while (tokens[++cursor] != ")") { while (tokens[++cursor] != ")") {
@ -214,49 +236,48 @@ inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, unsig
inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::shared_ptr<Env>& env) { inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::shared_ptr<Env>& env) {
if (!expr) { if (!expr) {
oops("syntax error"); oops("syntax error");
return null_expr; return nil;
} }
auto type = expr->type(); if (is_number(expr)) {
if (is_number(type)) {
return expr; return expr;
} }
if (type == Type::Symbol) { if (is_symbol(expr)) {
return env->get(std::static_pointer_cast<Symbol>(expr)); return env->get(get_value<Symbol>(expr));
}
if (type != Type::List) {
oops("syntax error");
} }
auto& value = std::static_pointer_cast<List>(expr)->value(); assert_type<Type::List>(expr);
std::shared_ptr<Symbol> _ = std::static_pointer_cast<Symbol>(value[0]); auto value = get_value<List>(expr);
auto& name = _->value(); assert_type<Type::Symbol>(value[0]);
auto name = get_value<Symbol>(value[0]);
if (name == "quote") { if (name == "quote") {
len_eq(expr, 2); assert_len(expr, 2);
return value[1]; return value[1];
} }
if (name == "def") { if (name == "def") {
len_eq(expr, 3); assert_len(expr, 3);
auto symbol = std::static_pointer_cast<Symbol>(value[1]); assert_type<Type::Symbol>(value[1]);
if (env->get(symbol)->type() != Type::Null) { auto symbol = get_value<Symbol>(value[1]);
oops("symbol defined: " + symbol->value()); if (!is_nil(env->get(symbol))) {
oops("symbol defined: " + symbol);
} }
env->put(symbol, eval(value[2], env)); env->put(symbol, eval(value[2], env));
return null_expr; return nil;
} }
if (name == "set!") { if (name == "set!") {
len_eq(expr, 3); assert_len(expr, 3);
auto symbol = std::static_pointer_cast<Symbol>(value[1]); assert_type<Type::Symbol>(value[1]);
auto symbol = get_value<Symbol>(value[1]);
env->put(symbol, eval(value[2], env)); env->put(symbol, eval(value[2], env));
return null_expr; return nil;
} }
if (name == "prog") { if (name == "prog") {
for (auto i = 1; i < value.size(); ++i) { for (auto i = 1; i < value.size(); ++i) {
eval(value[i], env); eval(value[i], env);
} }
return null_expr; return nil;
} }
if (name == "if") { if (name == "if") {
// (if (cond) (then body) (else body)) // (if (cond) (then body) (else body))
len_eq(expr, 4); assert_len(expr, 4);
if (is_true(eval(value[1], env))) { if (is_true(eval(value[1], env))) {
return eval(value[2], env); return eval(value[2], env);
} else { } else {
@ -265,23 +286,25 @@ inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::
} }
if (name == "while") { if (name == "while") {
// (while (cond) (loop body)) // (while (cond) (loop body))
len_eq(expr, 3); assert_len(expr, 3);
while (is_true(eval(value[1], env))) { while (is_true(eval(value[1], env))) {
eval(value[2], env); eval(value[2], env);
} }
return null_expr; return nil;
} }
if (name == "lambda") { if (name == "lambda") {
// (lambda (args) (body)) // (lambda (args) (body))
len_eq(expr, 3); assert_len(expr, 3);
auto lambda = [expr, parent = env](const std::shared_ptr<List>& args) { auto lambda = [expr, parent = env](const std::shared_ptr<List>& args) {
auto& value = std::static_pointer_cast<List>(expr)->value(); auto value = get_value<List>(expr);
auto symbols = std::static_pointer_cast<List>(value[1]); auto symbols = get_value<List>(value[1]);
// arguments bind // arguments bind
len_eq(symbols, args->value().size()); if (symbols.size() != args->value().size()) {
oops("arguments error");
}
auto env = std::make_shared<Env>(parent); auto env = std::make_shared<Env>(parent);
for (auto i = 0; i < symbols->value().size(); ++i) { for (auto i = 0; i < symbols.size(); ++i) {
auto symbol = std::static_pointer_cast<Symbol>(symbols->value()[i]); auto symbol = get_value<Symbol>(symbols[i]);
env->put(symbol, args->value()[i]); env->put(symbol, args->value()[i]);
} }
// eval body // eval body
@ -291,18 +314,18 @@ inline std::shared_ptr<Expr> eval(const std::shared_ptr<Expr>& expr, const std::
} }
// function/lambda call // function/lambda call
// (symbol arg1 arg2 arg3 ... ) // (symbol arg1 arg2 arg3 ... )
auto callable = env->get(_); auto callable = env->get(name);
if (!callable) { if (!callable) {
oops("unknow symbol: " + name); oops("unknow symbol: " + name);
} }
if (callable->type() != Type::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>(); auto args = std::make_shared<List>();
for (auto i = 1; i < value.size(); ++i) { for (auto i = 1; i < value.size(); ++i) {
args->append(eval(value[i], env)); args->append(eval(value[i], env));
} }
return std::static_pointer_cast<Callable>(callable)->value()(args); return get_value<Callable>(callable)(args);
} }
} // namespace lispoo } // namespace lispoo

Loading…
Cancel
Save