Everywhere: Add docstring support
This commit is contained in:
+6
-4
@@ -1,9 +1,11 @@
|
|||||||
|
|
||||||
(defn load-file [filename]
|
(defn load-file [file]
|
||||||
(eval (read-string (str "(do " (slurp filename) "\nnil)"))))
|
"Load the Lisp file named FILE."
|
||||||
|
(eval (read-string (str "(do " (slurp file) "\nnil)"))))
|
||||||
|
|
||||||
(defn load [filename]
|
(defn load [file]
|
||||||
(eval (read-string (str "(let* [] (do " (slurp filename) "))"))))
|
"Load the Lisp file named FILE."
|
||||||
|
(eval (read-string (str "(let* [] (do " (slurp file) "))"))))
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; eval: (emacs-lisp-mode)
|
;; eval: (emacs-lisp-mode)
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
(def! *host-language* "C++")
|
(def *host-language* "C++")
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; eval: (emacs-lisp-mode)
|
;; eval: (emacs-lisp-mode)
|
||||||
|
|||||||
+3
-2
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
(defn not [cond]
|
(defn not [object]
|
||||||
(if cond false true))
|
"Return true if OBJECT is nil or false, and return false otherwise."
|
||||||
|
(if object false true))
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; eval: (emacs-lisp-mode)
|
;; eval: (emacs-lisp-mode)
|
||||||
|
|||||||
+3
-1
@@ -225,8 +225,10 @@ Callable::Callable(ValuePtr meta)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
Function::Function(const std::string& name, FunctionType function)
|
Function::Function(std::string_view name, std::string_view signature, std::string_view documentation, FunctionType function)
|
||||||
: m_name(name)
|
: m_name(name)
|
||||||
|
, m_signature(signature)
|
||||||
|
, m_documentation(documentation)
|
||||||
, m_function(function)
|
, m_function(function)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -332,11 +332,13 @@ using FunctionType = std::function<ValuePtr(ValueVectorConstIt, ValueVectorConst
|
|||||||
|
|
||||||
class Function final : public Callable {
|
class Function final : public Callable {
|
||||||
public:
|
public:
|
||||||
Function(const std::string& name, FunctionType function);
|
Function(std::string_view name, std::string_view signature, std::string_view documentation, FunctionType function);
|
||||||
Function(const Function& that, ValuePtr meta);
|
Function(const Function& that, ValuePtr meta);
|
||||||
virtual ~Function() = default;
|
virtual ~Function() = default;
|
||||||
|
|
||||||
const std::string& name() const { return m_name; }
|
std::string_view name() const { return m_name; }
|
||||||
|
std::string_view signature() const { return m_signature; }
|
||||||
|
std::string_view documentation() const { return m_documentation; }
|
||||||
FunctionType function() const { return m_function; }
|
FunctionType function() const { return m_function; }
|
||||||
|
|
||||||
WITH_META(Function);
|
WITH_META(Function);
|
||||||
@@ -344,7 +346,9 @@ public:
|
|||||||
private:
|
private:
|
||||||
virtual bool isFunction() const override { return true; }
|
virtual bool isFunction() const override { return true; }
|
||||||
|
|
||||||
const std::string m_name;
|
std::string_view m_name;
|
||||||
|
std::string_view m_signature;
|
||||||
|
std::string_view m_documentation;
|
||||||
const FunctionType m_function;
|
const FunctionType m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Vendored
+10
-5
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
std::unordered_map<std::string, FunctionType> Environment::s_functions;
|
std::vector<FunctionParts> Environment::s_function_parts;
|
||||||
std::vector<std::string> Environment::s_lambdas;
|
std::vector<std::string> Environment::s_lambdas;
|
||||||
|
|
||||||
EnvironmentPtr Environment::create()
|
EnvironmentPtr Environment::create()
|
||||||
@@ -118,15 +118,20 @@ void Environment::loadFunctions()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Environment::registerFunction(const std::string& name, FunctionType function)
|
void Environment::registerFunction(FunctionParts function_parts)
|
||||||
{
|
{
|
||||||
s_functions.insert_or_assign(name, function);
|
s_function_parts.push_back(function_parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Environment::installFunctions(EnvironmentPtr env)
|
void Environment::installFunctions(EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
for (const auto& [name, function] : s_functions) {
|
for (const auto& function_parts : s_function_parts) {
|
||||||
env->set(name, makePtr<Function>(name, function));
|
env->set(std::string(function_parts.name),
|
||||||
|
makePtr<Function>(
|
||||||
|
function_parts.name,
|
||||||
|
function_parts.signature,
|
||||||
|
function_parts.documentation,
|
||||||
|
function_parts.function));
|
||||||
}
|
}
|
||||||
for (const auto& lambda : s_lambdas) {
|
for (const auto& lambda : s_lambdas) {
|
||||||
// Ensure all s-exprs are run with (do)
|
// Ensure all s-exprs are run with (do)
|
||||||
|
|||||||
Vendored
+10
-2
@@ -16,6 +16,14 @@
|
|||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
|
// All of these combined become a Function in the Environment
|
||||||
|
struct FunctionParts {
|
||||||
|
std::string_view name;
|
||||||
|
std::string_view signature;
|
||||||
|
std::string_view documentation;
|
||||||
|
FunctionType function;
|
||||||
|
};
|
||||||
|
|
||||||
class Environment {
|
class Environment {
|
||||||
public:
|
public:
|
||||||
virtual ~Environment() = default;
|
virtual ~Environment() = default;
|
||||||
@@ -26,7 +34,7 @@ public:
|
|||||||
static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments);
|
static EnvironmentPtr create(const ValuePtr lambda, ValueVector&& arguments);
|
||||||
|
|
||||||
static void loadFunctions();
|
static void loadFunctions();
|
||||||
static void registerFunction(const std::string& name, FunctionType function);
|
static void registerFunction(FunctionParts function_parts);
|
||||||
static void installFunctions(EnvironmentPtr env);
|
static void installFunctions(EnvironmentPtr env);
|
||||||
|
|
||||||
bool exists(const std::string& symbol);
|
bool exists(const std::string& symbol);
|
||||||
@@ -53,7 +61,7 @@ private:
|
|||||||
EnvironmentPtr m_outer { nullptr };
|
EnvironmentPtr m_outer { nullptr };
|
||||||
std::unordered_map<std::string, ValuePtr> m_values;
|
std::unordered_map<std::string, ValuePtr> m_values;
|
||||||
|
|
||||||
static std::unordered_map<std::string, FunctionType> s_functions;
|
static std::vector<FunctionParts> s_function_parts;
|
||||||
static std::vector<std::string> s_lambdas;
|
static std::vector<std::string> s_lambdas;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+14
@@ -21,6 +21,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (count {:foo 2 :bar 3}) -> 2
|
// (count {:foo 2 :bar 3}) -> 2
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"count",
|
"count",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("count", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("count", SIZE(), 1);
|
||||||
|
|
||||||
@@ -48,6 +50,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (first (list 1 2 3)) -> 1
|
// (first (list 1 2 3)) -> 1
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"first",
|
"first",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("first", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("first", SIZE(), 1);
|
||||||
|
|
||||||
@@ -64,6 +68,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (nth (list 1 2 3) 0) -> 1
|
// (nth (list 1 2 3) 0) -> 1
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"nth",
|
"nth",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("nth", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("nth", SIZE(), 2);
|
||||||
|
|
||||||
@@ -83,6 +89,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (rest (list 1 2 3)) -> (2 3)
|
// (rest (list 1 2 3)) -> (2 3)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"rest",
|
"rest",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("rest", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("rest", SIZE(), 1);
|
||||||
|
|
||||||
@@ -101,6 +109,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (get {:kw "value"} :kw) -> "value"
|
// (get {:kw "value"} :kw) -> "value"
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"get",
|
"get",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("get", SIZE(), 1);
|
||||||
|
|
||||||
@@ -123,6 +133,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (keys {"foo" 3 :bar 5}) -> ("foo" :bar)
|
// (keys {"foo" 3 :bar 5}) -> ("foo" :bar)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"keys",
|
"keys",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("keys", SIZE(), 1);
|
||||||
|
|
||||||
@@ -149,6 +161,8 @@ void Environment::loadCollectionAccess()
|
|||||||
// (vals {"foo" 3 :bar 5}) -> (3 5)
|
// (vals {"foo" 3 :bar 5}) -> (3 5)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"vals",
|
"vals",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("vals", SIZE(), 1);
|
||||||
|
|
||||||
|
|||||||
+10
@@ -19,6 +19,8 @@ void Environment::loadCollectionConstructor()
|
|||||||
// (list 1 2) -> (1 2)
|
// (list 1 2) -> (1 2)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"list",
|
"list",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
return makePtr<List>(begin, end);
|
return makePtr<List>(begin, end);
|
||||||
});
|
});
|
||||||
@@ -26,6 +28,8 @@ void Environment::loadCollectionConstructor()
|
|||||||
// (make-list 4 nil) -> (nil nil nil nil)
|
// (make-list 4 nil) -> (nil nil nil nil)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"make-list",
|
"make-list",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("make-list", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("make-list", SIZE(), 2);
|
||||||
|
|
||||||
@@ -80,6 +84,8 @@ void Environment::loadCollectionConstructor()
|
|||||||
// (vec (list 1 2 3))
|
// (vec (list 1 2 3))
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"vec",
|
"vec",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("vec", SIZE(), 1);
|
||||||
|
|
||||||
@@ -95,6 +101,8 @@ void Environment::loadCollectionConstructor()
|
|||||||
// (vector 1 2 3) -> [1 2 3]
|
// (vector 1 2 3) -> [1 2 3]
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"vector",
|
"vector",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
auto result = makePtr<Vector>();
|
auto result = makePtr<Vector>();
|
||||||
|
|
||||||
@@ -106,6 +114,8 @@ void Environment::loadCollectionConstructor()
|
|||||||
// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10}
|
// (hash-map "foo" 5 :bar 10) -> {"foo" 5 :bar 10}
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"hash-map",
|
"hash-map",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
|
CHECK_ARG_COUNT_EVEN("hash-map", SIZE());
|
||||||
|
|
||||||
|
|||||||
+18
@@ -21,6 +21,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
|
// (apply + 1 2 (list 3 4)) -> (+ 1 2 3 4) -> 10
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"apply",
|
"apply",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2);
|
CHECK_ARG_COUNT_AT_LEAST("apply", SIZE(), 2);
|
||||||
|
|
||||||
@@ -54,6 +56,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (cons 1 (list 2 3))
|
// (cons 1 (list 2 3))
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"cons",
|
"cons",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("cons", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("cons", SIZE(), 2);
|
||||||
|
|
||||||
@@ -73,6 +77,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (concat (list 1) (list 2 3)) -> (1 2 3)
|
// (concat (list 1) (list 2 3)) -> (1 2 3)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"concat",
|
"concat",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
for (auto it = begin; it != end; ++it) {
|
for (auto it = begin; it != end; ++it) {
|
||||||
@@ -95,6 +101,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (conj [1 2 3] 4 5 6) -> [1 2 3 4 5 6]
|
// (conj [1 2 3] 4 5 6) -> [1 2 3 4 5 6]
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"conj",
|
"conj",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("conj", SIZE(), 1);
|
||||||
|
|
||||||
@@ -123,6 +131,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6)
|
// (map (fn* (x) (* x 2)) (list 1 2 3)) -> (2 4 6)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"map",
|
"map",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("map", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("map", SIZE(), 2);
|
||||||
|
|
||||||
@@ -152,6 +162,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3)
|
// (set-nth (list 1 2 3) 1 "foo") -> (1 "foo" 3)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"set-nth",
|
"set-nth",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3);
|
CHECK_ARG_COUNT_IS("set-nth-element", SIZE(), 3);
|
||||||
|
|
||||||
@@ -180,6 +192,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (seq "foo") -> ("f" "o" "o")
|
// (seq "foo") -> ("f" "o" "o")
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"seq",
|
"seq",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("seq", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("seq", SIZE(), 1);
|
||||||
|
|
||||||
@@ -230,6 +244,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1}
|
// (assoc {:a 1 :b 2} :a 3 :c 1) -> {:a 3 :b 2 :c 1}
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"assoc",
|
"assoc",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("assoc", SIZE(), 1);
|
||||||
|
|
||||||
@@ -250,6 +266,8 @@ void Environment::loadCollectionModify()
|
|||||||
// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2}
|
// (dissoc {:a 1 :b 2 :c 3} :a :c :d) -> {:b 2}
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"dissoc",
|
"dissoc",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("dissoc", SIZE(), 1);
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
-4
@@ -40,10 +40,10 @@ void Environment::loadCompare()
|
|||||||
return makePtr<Constant>((result) ? Constant::True : Constant::False); \
|
return makePtr<Constant>((result) ? Constant::True : Constant::False); \
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_FUNCTION("<", NUMBER_COMPARE(<));
|
ADD_FUNCTION("<", "", "", NUMBER_COMPARE(<));
|
||||||
ADD_FUNCTION("<=", NUMBER_COMPARE(<=));
|
ADD_FUNCTION("<=", "", "", NUMBER_COMPARE(<=));
|
||||||
ADD_FUNCTION(">", NUMBER_COMPARE(>));
|
ADD_FUNCTION(">", "", "", NUMBER_COMPARE(>));
|
||||||
ADD_FUNCTION(">=", NUMBER_COMPARE(>=));
|
ADD_FUNCTION(">=", "", "", NUMBER_COMPARE(>=));
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
@@ -51,6 +51,8 @@ void Environment::loadCompare()
|
|||||||
// (= "foo" "foo") -> true
|
// (= "foo" "foo") -> true
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"=",
|
"=",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2);
|
CHECK_ARG_COUNT_AT_LEAST("=", SIZE(), 2);
|
||||||
|
|
||||||
|
|||||||
Vendored
+12
-2
@@ -18,6 +18,8 @@ void Environment::loadConvert()
|
|||||||
// (number-to-string 123) -> "123"
|
// (number-to-string 123) -> "123"
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"number-to-string",
|
"number-to-string",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("number-to-string", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("number-to-string", SIZE(), 1);
|
||||||
|
|
||||||
@@ -37,6 +39,8 @@ void Environment::loadConvert()
|
|||||||
// (string-to-char "123") -> 49
|
// (string-to-char "123") -> 49
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"string-to-char",
|
"string-to-char",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("string-to-char", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("string-to-char", SIZE(), 1);
|
||||||
|
|
||||||
@@ -49,6 +53,8 @@ void Environment::loadConvert()
|
|||||||
// (string-to-number "123") -> 123
|
// (string-to-number "123") -> 123
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"string-to-number",
|
"string-to-number",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("string-to-number", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("string-to-number", SIZE(), 1);
|
||||||
|
|
||||||
@@ -83,14 +89,16 @@ void Environment::loadConvert()
|
|||||||
|
|
||||||
// (string-to-list "foo") -> (102 111 111)
|
// (string-to-list "foo") -> (102 111 111)
|
||||||
// (string-to-vector "foo") -> [102 111 111]
|
// (string-to-vector "foo") -> [102 111 111]
|
||||||
ADD_FUNCTION("string-to-list", STRING_TO_COLLECTION("string-to-list", List));
|
ADD_FUNCTION("string-to-list", "", "", STRING_TO_COLLECTION("string-to-list", List));
|
||||||
ADD_FUNCTION("string-to-vector", STRING_TO_COLLECTION("string-to-vector", Vector));
|
ADD_FUNCTION("string-to-vector", "", "", STRING_TO_COLLECTION("string-to-vector", Vector));
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
|
||||||
// (symbol "foo") -> foo
|
// (symbol "foo") -> foo
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"symbol",
|
"symbol",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("symbol", SIZE(), 1);
|
||||||
|
|
||||||
@@ -107,6 +115,8 @@ void Environment::loadConvert()
|
|||||||
// (keyword 123) -> :123
|
// (keyword 123) -> :123
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"keyword",
|
"keyword",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("keyword", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("keyword", SIZE(), 1);
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-4
@@ -34,8 +34,8 @@ void Environment::loadFormat()
|
|||||||
return makePtr<String>(result); \
|
return makePtr<String>(result); \
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_FUNCTION("str", PRINTER_STRING(false, ""));
|
ADD_FUNCTION("str", "", "", PRINTER_STRING(false, ""));
|
||||||
ADD_FUNCTION("pr-str", PRINTER_STRING(true, " "));
|
ADD_FUNCTION("pr-str", "", "", PRINTER_STRING(true, " "));
|
||||||
|
|
||||||
#define PRINTER_PRINT(print_readably) \
|
#define PRINTER_PRINT(print_readably) \
|
||||||
{ \
|
{ \
|
||||||
@@ -52,8 +52,8 @@ void Environment::loadFormat()
|
|||||||
return makePtr<Constant>(); \
|
return makePtr<Constant>(); \
|
||||||
}
|
}
|
||||||
|
|
||||||
ADD_FUNCTION("prn", PRINTER_PRINT(true));
|
ADD_FUNCTION("prn", "", "", PRINTER_PRINT(true));
|
||||||
ADD_FUNCTION("println", PRINTER_PRINT(false));
|
ADD_FUNCTION("println", "", "", PRINTER_PRINT(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
Vendored
+4
@@ -17,6 +17,8 @@ void Environment::loadMeta()
|
|||||||
// (meta [1 2 3])
|
// (meta [1 2 3])
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"meta",
|
"meta",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("meta", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("meta", SIZE(), 1);
|
||||||
|
|
||||||
@@ -36,6 +38,8 @@ void Environment::loadMeta()
|
|||||||
// (with-meta [1 2 3] "some metadata")
|
// (with-meta [1 2 3] "some metadata")
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"with-meta",
|
"with-meta",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("with-meta", SIZE(), 2);
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
@@ -20,6 +20,8 @@ void Environment::loadMutable()
|
|||||||
// (atom 1)
|
// (atom 1)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"atom",
|
"atom",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("atom", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("atom", SIZE(), 1);
|
||||||
|
|
||||||
@@ -29,6 +31,8 @@ void Environment::loadMutable()
|
|||||||
// (deref myatom)
|
// (deref myatom)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"deref",
|
"deref",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("deref", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("deref", SIZE(), 1);
|
||||||
|
|
||||||
@@ -40,6 +44,8 @@ void Environment::loadMutable()
|
|||||||
// (reset! myatom 2)
|
// (reset! myatom 2)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"reset!",
|
"reset!",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("reset!", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("reset!", SIZE(), 2);
|
||||||
|
|
||||||
@@ -54,6 +60,8 @@ void Environment::loadMutable()
|
|||||||
// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
|
// (swap! myatom (fn* [x y] (+ 1 x y)) 2) -> (deref (def! myatom (atom ((fn* [x y] (+ 1 x y)) (deref myatom) 2))))
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"swap!",
|
"swap!",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2);
|
CHECK_ARG_COUNT_AT_LEAST("swap!", SIZE(), 2);
|
||||||
|
|
||||||
|
|||||||
Vendored
+13
@@ -16,6 +16,8 @@ void Environment::loadOperators()
|
|||||||
{
|
{
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"+",
|
"+",
|
||||||
|
"number...",
|
||||||
|
"Return the sum of any amount of arguments, where NUMBER is of type number.",
|
||||||
{
|
{
|
||||||
int64_t result = 0;
|
int64_t result = 0;
|
||||||
|
|
||||||
@@ -29,6 +31,11 @@ void Environment::loadOperators()
|
|||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"-",
|
"-",
|
||||||
|
"[number] subtract...",
|
||||||
|
R"(Negate NUMBER or SUBTRACT numbers and return the result.
|
||||||
|
|
||||||
|
With one arg, negates it. With more than one arg,
|
||||||
|
subtracts all but the first from the first.)",
|
||||||
{
|
{
|
||||||
size_t length = SIZE();
|
size_t length = SIZE();
|
||||||
if (length == 0) {
|
if (length == 0) {
|
||||||
@@ -54,6 +61,8 @@ void Environment::loadOperators()
|
|||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"*",
|
"*",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
int64_t result = 1;
|
int64_t result = 1;
|
||||||
|
|
||||||
@@ -67,6 +76,8 @@ void Environment::loadOperators()
|
|||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"/",
|
"/",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("/", SIZE(), 1);
|
||||||
|
|
||||||
@@ -86,6 +97,8 @@ void Environment::loadOperators()
|
|||||||
// (% 5 2) -> 1
|
// (% 5 2) -> 1
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"%",
|
"%",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("/", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("/", SIZE(), 2);
|
||||||
|
|
||||||
|
|||||||
Vendored
+4
-2
@@ -5,9 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <chrono> // std::chrono::sytem_clock
|
#include <chrono> // std::chrono::sytem_clock
|
||||||
#include <cstddef> // size_t
|
|
||||||
#include <cstdint> // int64_t
|
#include <cstdint> // int64_t
|
||||||
#include <memory> // std::static_pointer_cast
|
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "env/macro.h"
|
#include "env/macro.h"
|
||||||
@@ -22,6 +20,8 @@ void Environment::loadOther()
|
|||||||
// (throw x)
|
// (throw x)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"throw",
|
"throw",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("throw", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("throw", SIZE(), 1);
|
||||||
|
|
||||||
@@ -35,6 +35,8 @@ void Environment::loadOther()
|
|||||||
// (time-ms)
|
// (time-ms)
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"time-ms",
|
"time-ms",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0);
|
CHECK_ARG_COUNT_IS("time-ms", SIZE(), 0);
|
||||||
|
|
||||||
|
|||||||
Vendored
+20
-12
@@ -22,9 +22,9 @@ void Environment::loadPredicate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// (nil? nil)
|
// (nil? nil)
|
||||||
ADD_FUNCTION("nil?", IS_CONSTANT("nil?", Constant::Nil));
|
ADD_FUNCTION("nil?", "", "", IS_CONSTANT("nil?", Constant::Nil));
|
||||||
ADD_FUNCTION("true?", IS_CONSTANT("true?", Constant::True));
|
ADD_FUNCTION("true?", "", "", IS_CONSTANT("true?", Constant::True));
|
||||||
ADD_FUNCTION("false?", IS_CONSTANT("false?", Constant::False));
|
ADD_FUNCTION("false?", "", "", IS_CONSTANT("false?", Constant::False));
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
@@ -47,18 +47,20 @@ void Environment::loadPredicate()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// (symbol? 'foo)
|
// (symbol? 'foo)
|
||||||
ADD_FUNCTION("atom?", IS_TYPE(Atom));
|
ADD_FUNCTION("atom?", "", "", IS_TYPE(Atom));
|
||||||
ADD_FUNCTION("keyword?", IS_TYPE(Keyword));
|
ADD_FUNCTION("keyword?", "", "", IS_TYPE(Keyword));
|
||||||
ADD_FUNCTION("list?", IS_TYPE(List));
|
ADD_FUNCTION("list?", "", "", IS_TYPE(List));
|
||||||
ADD_FUNCTION("map?", IS_TYPE(HashMap));
|
ADD_FUNCTION("map?", "", "", IS_TYPE(HashMap));
|
||||||
ADD_FUNCTION("number?", IS_TYPE(Number));
|
ADD_FUNCTION("number?", "", "", IS_TYPE(Number));
|
||||||
ADD_FUNCTION("sequential?", IS_TYPE(Collection));
|
ADD_FUNCTION("sequential?", "", "", IS_TYPE(Collection));
|
||||||
ADD_FUNCTION("string?", IS_TYPE(String));
|
ADD_FUNCTION("string?", "", "", IS_TYPE(String));
|
||||||
ADD_FUNCTION("symbol?", IS_TYPE(Symbol));
|
ADD_FUNCTION("symbol?", "", "", IS_TYPE(Symbol));
|
||||||
ADD_FUNCTION("vector?", IS_TYPE(Vector));
|
ADD_FUNCTION("vector?", "", "", IS_TYPE(Vector));
|
||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"fn?",
|
"fn?",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
@@ -78,6 +80,8 @@ void Environment::loadPredicate()
|
|||||||
|
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"macro?",
|
"macro?",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
@@ -101,6 +105,8 @@ void Environment::loadPredicate()
|
|||||||
// (contains? {"bar" 5} "foo") -> false
|
// (contains? {"bar" 5} "foo") -> false
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"contains?",
|
"contains?",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
|
CHECK_ARG_COUNT_IS("contains?", SIZE(), 2);
|
||||||
|
|
||||||
@@ -117,6 +123,8 @@ void Environment::loadPredicate()
|
|||||||
// (empty? [] [1 2 3] []) -> false
|
// (empty? [] [1 2 3] []) -> false
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"empty?",
|
"empty?",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
@@ -19,6 +19,8 @@ void Environment::loadRepl()
|
|||||||
// REPL reader
|
// REPL reader
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"read-string",
|
"read-string",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("read-string", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("read-string", SIZE(), 1);
|
||||||
|
|
||||||
@@ -31,6 +33,8 @@ void Environment::loadRepl()
|
|||||||
// Read file contents
|
// Read file contents
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"slurp",
|
"slurp",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("slurp", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("slurp", SIZE(), 1);
|
||||||
|
|
||||||
@@ -45,6 +49,8 @@ void Environment::loadRepl()
|
|||||||
// Prompt readline
|
// Prompt readline
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"readline",
|
"readline",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("readline", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("readline", SIZE(), 1);
|
||||||
|
|
||||||
@@ -56,6 +62,8 @@ void Environment::loadRepl()
|
|||||||
// REPL eval
|
// REPL eval
|
||||||
ADD_FUNCTION(
|
ADD_FUNCTION(
|
||||||
"eval",
|
"eval",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("eval", SIZE(), 1);
|
CHECK_ARG_COUNT_IS("eval", SIZE(), 1);
|
||||||
|
|
||||||
|
|||||||
Vendored
+6
-4
@@ -8,9 +8,11 @@
|
|||||||
|
|
||||||
#include "env/environment.h"
|
#include "env/environment.h"
|
||||||
|
|
||||||
#define ADD_FUNCTION(symbol, lambda) \
|
#define ADD_FUNCTION(name, signature, documentation, lambda) \
|
||||||
Environment::registerFunction( \
|
Environment::registerFunction( \
|
||||||
symbol, \
|
{ name, \
|
||||||
[](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda);
|
signature, \
|
||||||
|
documentation, \
|
||||||
|
[](ValueVectorConstIt begin, ValueVectorConstIt end) -> blaze::ValuePtr lambda });
|
||||||
|
|
||||||
#define SIZE() std::distance(begin, end)
|
#define SIZE() std::distance(begin, end)
|
||||||
|
|||||||
+190
-13
@@ -4,17 +4,26 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <iterator> // std::distance, std::next, std::prev
|
#include <algorithm> // std::find_if, std::transform
|
||||||
|
#include <cctype> // std::toupper
|
||||||
|
#include <iterator> // std::distance, std::next, std::prev
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ruc/format/color.h"
|
||||||
|
#include "ruc/format/format.h"
|
||||||
|
#include "ruc/format/print.h"
|
||||||
|
|
||||||
#include "ast.h"
|
#include "ast.h"
|
||||||
#include "env/environment.h"
|
#include "env/environment.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "eval.h"
|
#include "eval.h"
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
|
#include "macro.h"
|
||||||
|
#include "printer.h"
|
||||||
|
#include "settings.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@@ -22,7 +31,7 @@ namespace blaze {
|
|||||||
|
|
||||||
static ValuePtr evalQuasiQuoteImpl(ValuePtr ast);
|
static ValuePtr evalQuasiQuoteImpl(ValuePtr ast);
|
||||||
|
|
||||||
// (def! x 2)
|
EVAL_FUNCTION("def!", "symbol value", "Set SYMBOL to the value VALUE.");
|
||||||
ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
|
ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("def!", nodes.size(), 2);
|
CHECK_ARG_COUNT_IS("def!", nodes.size(), 2);
|
||||||
@@ -44,7 +53,13 @@ ValuePtr Eval::evalDef(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return env->set(symbol->symbol(), value);
|
return env->set(symbol->symbol(), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// (defmacro! x (fn* (x) x))
|
EVAL_FUNCTION("defmacro!", "symbol function",
|
||||||
|
R"(Define SYMBOL as a macro.
|
||||||
|
|
||||||
|
When the macro is called, as in (NAME ARGS...),
|
||||||
|
the FUNCTION (fn* ARGLIST BODY...) is applied to
|
||||||
|
the list ARGS... as it appears in the expression,
|
||||||
|
and the result should be a form to be evaluated instead of the original.)");
|
||||||
ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
|
ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("defmacro!", nodes.size(), 2);
|
CHECK_ARG_COUNT_IS("defmacro!", nodes.size(), 2);
|
||||||
@@ -67,7 +82,139 @@ ValuePtr Eval::evalDefMacro(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return env->set(symbol->symbol(), makePtr<Macro>(*lambda));
|
return env->set(symbol->symbol(), makePtr<Macro>(*lambda));
|
||||||
}
|
}
|
||||||
|
|
||||||
// (fn* (x) x)
|
EVAL_FUNCTION("describe", "symbol", "Display the full documentation of SYMBOL.");
|
||||||
|
ValuePtr Eval::evalDescribe(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
|
{
|
||||||
|
CHECK_ARG_COUNT_IS("describe", nodes.size(), 1);
|
||||||
|
|
||||||
|
// First argument needs to be a Symbol
|
||||||
|
VALUE_CAST(symbol, Symbol, nodes.front());
|
||||||
|
auto symbol_string = symbol->symbol();
|
||||||
|
|
||||||
|
std::string type;
|
||||||
|
std::string signature;
|
||||||
|
std::string documentation;
|
||||||
|
std::string value_string;
|
||||||
|
|
||||||
|
bool pretty_print = Settings::the().get("pretty-print") == "1";
|
||||||
|
auto bold = fg(ruc::format::TerminalColor::None) | ruc::format::Emphasis::Bold;
|
||||||
|
|
||||||
|
auto describe = [&]() {
|
||||||
|
print("{} is a {}.\n\n", symbol_string, type);
|
||||||
|
|
||||||
|
if (!signature.empty()) {
|
||||||
|
pretty_print ? print(bold, "Signature\n") : print("Signature\n");
|
||||||
|
print("({})\n", signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!documentation.empty()) {
|
||||||
|
pretty_print ? print(bold, "\nDocumentation\n") : print("\nDocumentation\n");
|
||||||
|
print("{}\n", documentation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!value_string.empty()) {
|
||||||
|
pretty_print ? print(bold, "Value\n") : print("Value\n");
|
||||||
|
print("{}\n", value_string);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Verify if symbol is a special form
|
||||||
|
auto special_form = std::find_if(
|
||||||
|
s_special_form_parts.begin(),
|
||||||
|
s_special_form_parts.end(),
|
||||||
|
[&symbol_string](const SpecialFormParts& special_form_parts) {
|
||||||
|
return special_form_parts.name == symbol_string;
|
||||||
|
});
|
||||||
|
|
||||||
|
// If symbol is not special form, lookup in the environment
|
||||||
|
ValuePtr value;
|
||||||
|
if (special_form == s_special_form_parts.end()) {
|
||||||
|
value = env->get(symbol_string);
|
||||||
|
if (!value) {
|
||||||
|
Error::the().add(format("'{}' not found", symbol_string));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Variable
|
||||||
|
if (special_form == s_special_form_parts.end() && !is<Callable>(value.get())) {
|
||||||
|
type = "variable";
|
||||||
|
|
||||||
|
Printer printer;
|
||||||
|
value_string = format("{}", printer.printNoErrorCheck(value, true));
|
||||||
|
|
||||||
|
describe();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
signature = pretty_print ? format(fg(ruc::format::TerminalColor::BrightBlue), "{}", symbol_string)
|
||||||
|
: symbol_string;
|
||||||
|
|
||||||
|
// Special form
|
||||||
|
if (special_form != s_special_form_parts.end()) {
|
||||||
|
type = "special form";
|
||||||
|
|
||||||
|
std::string signature_lower = std::string(special_form->signature);
|
||||||
|
std::transform(signature_lower.begin(), signature_lower.end(), signature_lower.begin(), ::toupper);
|
||||||
|
signature += !signature_lower.empty() ? " " : "";
|
||||||
|
signature += signature_lower;
|
||||||
|
|
||||||
|
documentation = special_form->documentation;
|
||||||
|
|
||||||
|
describe();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function / lambda / macro
|
||||||
|
if (is<Function>(value.get())) {
|
||||||
|
type = "function";
|
||||||
|
|
||||||
|
auto function = std::static_pointer_cast<Function>(value);
|
||||||
|
signature += !function->signature().empty() ? " " : "";
|
||||||
|
signature += function->signature();
|
||||||
|
|
||||||
|
documentation = function->documentation();
|
||||||
|
}
|
||||||
|
else if (is<Lambda>(value.get()) || is<Macro>(value.get())) {
|
||||||
|
type = is<Lambda>(value.get()) ? "function" : "macro";
|
||||||
|
|
||||||
|
auto lambda = std::static_pointer_cast<Lambda>(value);
|
||||||
|
auto bindings = lambda->bindings();
|
||||||
|
std::string binding;
|
||||||
|
for (size_t i = 0; i < bindings.size(); ++i) {
|
||||||
|
binding = bindings[i];
|
||||||
|
std::transform(binding.begin(), binding.end(), binding.begin(), ::toupper);
|
||||||
|
signature += " " + binding;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto body = lambda->body();
|
||||||
|
if (is<String>(body.get())) {
|
||||||
|
documentation = std::static_pointer_cast<String>(body)->data();
|
||||||
|
}
|
||||||
|
else if (is<List>(body.get())) {
|
||||||
|
VALUE_CAST(list, List, body);
|
||||||
|
if (list->size() > 1) {
|
||||||
|
auto second = list->nodesRead()[1];
|
||||||
|
if (is<String>(second.get())) {
|
||||||
|
documentation = std::static_pointer_cast<String>(second)->data();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
describe();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVAL_FUNCTION("fn*", "args [docstring] body...", R"(Return an anonymous function.
|
||||||
|
|
||||||
|
ARGS should take the form of an argument list or vector.
|
||||||
|
DOCSTRING is an optional documentation string.
|
||||||
|
If present, it should describe how to call the function.
|
||||||
|
BODY should be a list of Lisp expressions.)");
|
||||||
ValuePtr Eval::evalFn(const ValueVector& nodes, EnvironmentPtr env)
|
ValuePtr Eval::evalFn(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("fn*", nodes.size(), 2);
|
CHECK_ARG_COUNT_AT_LEAST("fn*", nodes.size(), 2);
|
||||||
@@ -102,6 +249,7 @@ ValuePtr Eval::evalFn(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
// (quasiquoteexpand x)
|
// (quasiquoteexpand x)
|
||||||
|
EVAL_FUNCTION("quasiquoteexpand", "arg", ""); // TODO
|
||||||
ValuePtr Eval::evalQuasiQuoteExpand(const ValueVector& nodes)
|
ValuePtr Eval::evalQuasiQuoteExpand(const ValueVector& nodes)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("quasiquoteexpand", nodes.size(), 1);
|
CHECK_ARG_COUNT_IS("quasiquoteexpand", nodes.size(), 1);
|
||||||
@@ -109,7 +257,7 @@ ValuePtr Eval::evalQuasiQuoteExpand(const ValueVector& nodes)
|
|||||||
return evalQuasiQuoteImpl(nodes.front());
|
return evalQuasiQuoteImpl(nodes.front());
|
||||||
}
|
}
|
||||||
|
|
||||||
// (quote x)
|
EVAL_FUNCTION("quote", "arg", "Return the ARG, without evaluating it. (quote x) yields x.");
|
||||||
ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("quote", nodes.size(), 1);
|
CHECK_ARG_COUNT_IS("quote", nodes.size(), 1);
|
||||||
@@ -117,7 +265,13 @@ ValuePtr Eval::evalQuote(const ValueVector& nodes)
|
|||||||
return nodes.front();
|
return nodes.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
// (try* x ... (catch* y z))
|
EVAL_FUNCTION("try*", "body... [catch]", R"(Eval BODY allowing exceptions to get caught.
|
||||||
|
|
||||||
|
CATCH should take the form of (catch* binding handler).
|
||||||
|
|
||||||
|
The BODY is evaluated, if it throws an exception, then form CATCH is
|
||||||
|
handled by creating a new environment that binds the symbol BINDING
|
||||||
|
to the value of the exception that was thrown. Finally, HANDLER is evaluated.)");
|
||||||
ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1);
|
CHECK_ARG_COUNT_AT_LEAST("try*", nodes.size(), 1);
|
||||||
@@ -169,11 +323,11 @@ ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
|
|
||||||
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())));
|
VALUE_CAST(catch_binding, Symbol, (*std::next(catch_nodes.begin())));
|
||||||
|
|
||||||
// Create new Environment that binds 'y' to the value of the exception
|
// Create new Environment that binds 'binding' to the value of the exception
|
||||||
auto catch_env = Environment::create(env);
|
auto catch_env = Environment::create(env);
|
||||||
catch_env->set(catch_binding->symbol(), error);
|
catch_env->set(catch_binding->symbol(), error);
|
||||||
|
|
||||||
// Evaluate 'z' using the new Environment
|
// Evaluate 'handler' using the new Environment
|
||||||
m_ast = catch_nodes.back();
|
m_ast = catch_nodes.back();
|
||||||
m_env = catch_env;
|
m_env = catch_env;
|
||||||
return evalImpl();
|
return evalImpl();
|
||||||
@@ -181,7 +335,10 @@ ValuePtr Eval::evalTry(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
// (and 1 2 3)
|
EVAL_FUNCTION("and", "args...", R"(Eval ARGS until one of them yields nil, then return nil.
|
||||||
|
|
||||||
|
The remaining args are not evalled at all.
|
||||||
|
If no arg yields nil, return the last arg's value.)");
|
||||||
void Eval::evalAnd(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalAnd(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
ValuePtr result = makePtr<Constant>(Constant::True);
|
ValuePtr result = makePtr<Constant>(Constant::True);
|
||||||
@@ -205,7 +362,7 @@ void Eval::evalAnd(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
return; // TCO
|
||||||
}
|
}
|
||||||
|
|
||||||
// (do 1 2 3)
|
EVAL_FUNCTION("do", "body...", "Eval BODY forms sequentially and return value of the last one.");
|
||||||
void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("do", nodes.size(), 1, void());
|
CHECK_ARG_COUNT_AT_LEAST("do", nodes.size(), 1, void());
|
||||||
@@ -223,7 +380,11 @@ void Eval::evalDo(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
return; // TCO
|
||||||
}
|
}
|
||||||
|
|
||||||
// (if x true false)
|
EVAL_FUNCTION("if", "COND THEN [ELSE]", R"(If COND yields non-nil, do THEN, else do ELSE.
|
||||||
|
|
||||||
|
Returns the value of THEN or the value of ELSE.
|
||||||
|
Both THEN and ELSE must be one expression.
|
||||||
|
If COND yields nil, and there is no ELSE, the value is nil.)");
|
||||||
void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_BETWEEN("if", nodes.size(), 2, 3, void());
|
CHECK_ARG_COUNT_BETWEEN("if", nodes.size(), 2, 3, void());
|
||||||
@@ -247,7 +408,12 @@ void Eval::evalIf(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
return; // TCO
|
return; // TCO
|
||||||
}
|
}
|
||||||
|
|
||||||
// (let* (x 1) x)
|
EVAL_FUNCTION("let*", "varlist body", R"(Bind variables accoring to VARLIST then eval BODY.
|
||||||
|
|
||||||
|
The value of the BODY form is returned.
|
||||||
|
VARLIST is a list or vector with an even amount of elements,
|
||||||
|
where each odd number is a symbol gets bind the even element.
|
||||||
|
All even elements are evalled before any symbols are bound.)");
|
||||||
void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalLet(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("let*", nodes.size(), 2, void());
|
CHECK_ARG_COUNT_IS("let*", nodes.size(), 2, void());
|
||||||
@@ -307,6 +473,7 @@ static bool isMacroCall(ValuePtr ast, EnvironmentPtr env)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EVAL_FUNCTION("macroexpand-1", "expression", "Macroexpand EXPRESSION and pretty-print its value.");
|
||||||
void Eval::evalMacroExpand1(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalMacroExpand1(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("macroexpand-1", nodes.size(), 1, void());
|
CHECK_ARG_COUNT_IS("macroexpand-1", nodes.size(), 1, void());
|
||||||
@@ -329,7 +496,10 @@ void Eval::evalMacroExpand1(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
// (or 1 2 3)
|
EVAL_FUNCTION("or", "args...", R"(Eval ARGS until one of them yields non-nil, then return that value.
|
||||||
|
|
||||||
|
The remaining args are not evalled at all.
|
||||||
|
If all args return nil, return nil.)");
|
||||||
void Eval::evalOr(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalOr(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
ValuePtr result;
|
ValuePtr result;
|
||||||
@@ -442,6 +612,7 @@ static ValuePtr evalQuasiQuoteImpl(ValuePtr ast)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// (quasiquote x)
|
// (quasiquote x)
|
||||||
|
EVAL_FUNCTION("quasiquote", "arg", R"()"); // TODO
|
||||||
void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_IS("quasiquote", nodes.size(), 1, void());
|
CHECK_ARG_COUNT_IS("quasiquote", nodes.size(), 1, void());
|
||||||
@@ -456,6 +627,12 @@ void Eval::evalQuasiQuote(const ValueVector& nodes, EnvironmentPtr env)
|
|||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
// (while true body...)
|
// (while true body...)
|
||||||
|
EVAL_FUNCTION("while", "test body...", R"(If TEST yields non-nil, eval BODY... and repeat
|
||||||
|
|
||||||
|
The order of execution is thus TEST, BODY, TEST, BODY and so on
|
||||||
|
until TEST returns nil.
|
||||||
|
|
||||||
|
The value of a while form is always nil.)");
|
||||||
void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
|
void Eval::evalWhile(const ValueVector& nodes, EnvironmentPtr env)
|
||||||
{
|
{
|
||||||
CHECK_ARG_COUNT_AT_LEAST("while", nodes.size(), 2, void());
|
CHECK_ARG_COUNT_AT_LEAST("while", nodes.size(), 2, void());
|
||||||
|
|||||||
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
|
std::vector<SpecialFormParts> Eval::s_special_form_parts;
|
||||||
|
|
||||||
Eval::Eval(ValuePtr ast, EnvironmentPtr env)
|
Eval::Eval(ValuePtr ast, EnvironmentPtr env)
|
||||||
: m_ast(ast)
|
: m_ast(ast)
|
||||||
, m_env(env)
|
, m_env(env)
|
||||||
@@ -29,6 +31,11 @@ Eval::Eval(ValuePtr ast, EnvironmentPtr env)
|
|||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
|
|
||||||
|
void Eval::registerSpecialForm(SpecialFormParts special_form_parts)
|
||||||
|
{
|
||||||
|
s_special_form_parts.push_back(special_form_parts);
|
||||||
|
}
|
||||||
|
|
||||||
void Eval::eval()
|
void Eval::eval()
|
||||||
{
|
{
|
||||||
m_ast = evalImpl();
|
m_ast = evalImpl();
|
||||||
@@ -80,6 +87,9 @@ ValuePtr Eval::evalImpl()
|
|||||||
if (symbol == "defmacro!") {
|
if (symbol == "defmacro!") {
|
||||||
return evalDefMacro(nodes, env);
|
return evalDefMacro(nodes, env);
|
||||||
}
|
}
|
||||||
|
if (symbol == "describe") {
|
||||||
|
return evalDescribe(nodes, env);
|
||||||
|
}
|
||||||
if (symbol == "fn*") {
|
if (symbol == "fn*") {
|
||||||
return evalFn(nodes, env);
|
return evalFn(nodes, env);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -6,21 +6,27 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <list>
|
#include <vector>
|
||||||
#include <stack>
|
|
||||||
|
|
||||||
#include "env/environment.h"
|
#include "env/environment.h"
|
||||||
#include "forward.h"
|
#include "forward.h"
|
||||||
|
|
||||||
namespace blaze {
|
namespace blaze {
|
||||||
|
|
||||||
class List;
|
// All of these combined become a Function in the Environment
|
||||||
|
struct SpecialFormParts {
|
||||||
|
std::string_view name;
|
||||||
|
std::string_view signature;
|
||||||
|
std::string_view documentation;
|
||||||
|
};
|
||||||
|
|
||||||
class Eval {
|
class Eval {
|
||||||
public:
|
public:
|
||||||
Eval(ValuePtr ast, EnvironmentPtr env);
|
Eval(ValuePtr ast, EnvironmentPtr env);
|
||||||
virtual ~Eval() = default;
|
virtual ~Eval() = default;
|
||||||
|
|
||||||
|
static void registerSpecialForm(SpecialFormParts special_form_parts);
|
||||||
|
|
||||||
void eval();
|
void eval();
|
||||||
|
|
||||||
ValuePtr ast() const { return m_ast; }
|
ValuePtr ast() const { return m_ast; }
|
||||||
@@ -33,6 +39,7 @@ private:
|
|||||||
|
|
||||||
ValuePtr evalDef(const ValueVector& nodes, EnvironmentPtr env);
|
ValuePtr evalDef(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
ValuePtr evalDefMacro(const ValueVector& nodes, EnvironmentPtr env);
|
ValuePtr evalDefMacro(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
|
ValuePtr evalDescribe(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
ValuePtr evalFn(const ValueVector& nodes, EnvironmentPtr env);
|
ValuePtr evalFn(const ValueVector& nodes, EnvironmentPtr env);
|
||||||
ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
|
ValuePtr evalQuasiQuoteExpand(const ValueVector& nodes);
|
||||||
ValuePtr evalQuote(const ValueVector& nodes);
|
ValuePtr evalQuote(const ValueVector& nodes);
|
||||||
@@ -52,6 +59,8 @@ private:
|
|||||||
ValuePtr m_ast;
|
ValuePtr m_ast;
|
||||||
EnvironmentPtr m_env;
|
EnvironmentPtr m_env;
|
||||||
EnvironmentPtr m_outer_env;
|
EnvironmentPtr m_outer_env;
|
||||||
|
|
||||||
|
static std::vector<SpecialFormParts> s_special_form_parts;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace blaze
|
} // namespace blaze
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2023 Riyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "eval.h"
|
||||||
|
|
||||||
|
#define CONCAT(a, b) CONCAT_IMPL(a, b)
|
||||||
|
#define CONCAT_IMPL(a, b) a##b
|
||||||
|
|
||||||
|
#define EVAL_FUNCTION_IMPL(name, signature, documentation, struct_name) \
|
||||||
|
struct struct_name { \
|
||||||
|
struct_name() \
|
||||||
|
{ \
|
||||||
|
Eval::registerSpecialForm({ name, signature, documentation }); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
static struct struct_name struct_name; // NOLINT(clang-diagnostic-unused-function)
|
||||||
|
|
||||||
|
#define EVAL_FUNCTION(name, signature, documentation) \
|
||||||
|
EVAL_FUNCTION_IMPL(name, signature, documentation, CONCAT(__EVAL_STRUCT_, __COUNTER__))
|
||||||
Reference in New Issue
Block a user