|
|
@ -1,13 +1,12 @@ |
|
|
#pragma once |
|
|
#pragma once |
|
|
|
|
|
|
|
|
#include <iostream> |
|
|
|
|
|
#include <exception> |
|
|
#include <exception> |
|
|
|
|
|
|
|
|
#include <string> |
|
|
|
|
|
#include <vector> |
|
|
|
|
|
#include <memory> |
|
|
|
|
|
#include <functional> |
|
|
#include <functional> |
|
|
|
|
|
#include <iostream> |
|
|
|
|
|
#include <memory> |
|
|
|
|
|
#include <string> |
|
|
#include <unordered_map> |
|
|
#include <unordered_map> |
|
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
namespace lispoo { |
|
|
namespace lispoo { |
|
|
|
|
|
|
|
|
@ -28,75 +27,73 @@ enum class Type { |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Expr { |
|
|
class Expr { |
|
|
public: |
|
|
public: |
|
|
virtual Type type() = 0; |
|
|
virtual Type type() = 0; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
template <typename T> |
|
|
template <typename T> |
|
|
class Atom: public Expr { |
|
|
class Atom : public Expr { |
|
|
public: |
|
|
public: |
|
|
explicit Atom(const T& value) : value_(value) {} |
|
|
explicit Atom(const T& value) : value_(value) {} |
|
|
Type type() override { return Type::Atom; } |
|
|
Type type() override { return Type::Atom; } |
|
|
const T& value() const { return value_; } |
|
|
const T& value() const { return value_; } |
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
T value_; |
|
|
T value_; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Symbol: public Atom<std::string> { |
|
|
class Symbol : public Atom<std::string> { |
|
|
public: |
|
|
public: |
|
|
explicit Symbol(const std::string& value) : Atom(value) {} |
|
|
explicit Symbol(const std::string& value) : Atom(value) {} |
|
|
Type type() override { return Type::Symbol; } |
|
|
Type type() override { return Type::Symbol; } |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Integer: public Atom<long> { |
|
|
class Integer : public Atom<long> { |
|
|
public: |
|
|
public: |
|
|
explicit Integer(const long& value) : Atom(value) {} |
|
|
explicit Integer(const long& value) : Atom(value) {} |
|
|
Type type() override { return Type::Integer; } |
|
|
Type type() override { return Type::Integer; } |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Float: public Atom<double> { |
|
|
class Float : public Atom<double> { |
|
|
public: |
|
|
public: |
|
|
explicit Float(const double& value) : Atom(value) {} |
|
|
explicit Float(const double& value) : Atom(value) {} |
|
|
Type type() override { return Type::Float; } |
|
|
Type type() override { return Type::Float; } |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Null: public Expr { |
|
|
class Null : public Expr { |
|
|
public: |
|
|
public: |
|
|
Type type() override { return Type::Null; } |
|
|
Type type() override { return Type::Null; } |
|
|
}; |
|
|
}; |
|
|
static const std::shared_ptr<Expr> nil = 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_; } |
|
|
const std::vector<std::shared_ptr<Expr>>& value() const { 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: |
|
|
std::vector<std::shared_ptr<Expr>> value_; |
|
|
std::vector<std::shared_ptr<Expr>> value_; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
class Env; |
|
|
class Env; |
|
|
class Callable: public Expr { |
|
|
class Callable : public Expr { |
|
|
public: |
|
|
public: |
|
|
using Fn = std::function<std::shared_ptr<Expr>(const std::shared_ptr<Expr>&, |
|
|
using Fn = std::function<std::shared_ptr<Expr>( |
|
|
const std::shared_ptr<Env>& env)>; |
|
|
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; } |
|
|
const Fn& value() const { |
|
|
const Fn& value() const { return lambda_; } |
|
|
return lambda_; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
private: |
|
|
Fn lambda_; |
|
|
Fn lambda_; |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// environment
|
|
|
// 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::string& symbol) const { |
|
|
std::shared_ptr<Expr> get(const std::string& symbol) const { |
|
|
@ -113,20 +110,20 @@ public: |
|
|
expr_map_[symbol] = expr; |
|
|
expr_map_[symbol] = 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 putenv(const std::string& symbol, Callable::Fn&& lambda) { |
|
|
global->put(symbol, std::make_shared<Callable>(std::forward<Callable::Fn>(lambda))); |
|
|
global->put(symbol, |
|
|
|
|
|
std::make_shared<Callable>(std::forward<Callable::Fn>(lambda))); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// type utils
|
|
|
// type utils
|
|
|
|
|
|
|
|
|
inline bool is_par(char ch) { |
|
|
inline bool is_par(char ch) { return ch == '(' || ch == ')'; } |
|
|
return ch == '(' || ch == ')'; |
|
|
|
|
|
} |
|
|
|
|
|
template <typename T> |
|
|
template <typename T> |
|
|
inline decltype(auto) get_value(const std::shared_ptr<Expr>& expr) { |
|
|
inline decltype(auto) get_value(const std::shared_ptr<Expr>& expr) { |
|
|
return std::static_pointer_cast<T>(expr)->value(); |
|
|
return std::static_pointer_cast<T>(expr)->value(); |
|
|
@ -184,13 +181,15 @@ inline void tokenize(const std::string& str, std::vector<std::string>& tokens) { |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
auto s = i; |
|
|
auto s = i; |
|
|
for (; !(std::isspace(str[i]) || is_par(str[i])); ++i); |
|
|
for (; !(std::isspace(str[i]) || is_par(str[i])); ++i) |
|
|
|
|
|
; |
|
|
tokens.emplace_back(str.c_str() + s, i - s); |
|
|
tokens.emplace_back(str.c_str() + s, i - s); |
|
|
i--; |
|
|
i--; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
inline std::shared_ptr<Expr> parse_atom(const std::vector<std::string>& tokens, long& cursor) { |
|
|
inline std::shared_ptr<Expr> parse_atom(const std::vector<std::string>& tokens, |
|
|
|
|
|
long& cursor) { |
|
|
auto token = tokens[cursor]; |
|
|
auto token = tokens[cursor]; |
|
|
auto type = Type::Symbol; |
|
|
auto type = Type::Symbol; |
|
|
if (std::isdigit(token[0]) || token[0] == '-') { |
|
|
if (std::isdigit(token[0]) || token[0] == '-') { |
|
|
@ -221,7 +220,8 @@ inline std::shared_ptr<Expr> parse_atom(const std::vector<std::string>& tokens, |
|
|
return nil; |
|
|
return nil; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, long& cursor) { |
|
|
inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, |
|
|
|
|
|
long& cursor) { |
|
|
if (cursor >= tokens.size()) { |
|
|
if (cursor >= tokens.size()) { |
|
|
oops("parse error"); |
|
|
oops("parse error"); |
|
|
} |
|
|
} |
|
|
@ -235,7 +235,8 @@ inline std::shared_ptr<Expr> parse(const std::vector<std::string>& tokens, long& |
|
|
return parse_atom(tokens, cursor); |
|
|
return parse_atom(tokens, cursor); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
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 nil; |
|
|
return nil; |
|
|
|