#pragma once #include #include #include #include #include const std::string VERSION = "ml 0.2 (" __DATE__ " " __TIME__ ")"; const std::string STDLIB_LOADER = R"( (do (define ___lib_path "/usr/local/var/mlisp") (if (is-dir? ___lib_path) (for file (ls-dir ___lib_path) (if (string-regex? file "^stdlib\.lsp$") (include (+ ___lib_path "/" file))) ))) )"; // Forward declaration for MlEnvironment class definition class MlValue; // An instance of a function's scope. class MlEnvironment { public: // Default constructor MlEnvironment() : parent_scope(nullptr) {} // Does this environment, or its parent environment, // have this atom in scope? // This is only used to determine which atoms to capture when // creating a lambda function. bool has(const std::string &name) const; // Get the value associated with this name in this scope MlValue get(const std::string &name) const; // Set the value associated with this name in this scope void set(const std::string &name, MlValue value); // Set the value associated with this name in this scope and parent scopes // and if not exists sets in this scope void setX(const std::string &name, MlValue value); // Get vector of executables in this scope std::vector get_lambdas_list() const; void combine(MlEnvironment const &other); void set_parent_scope(MlEnvironment *parent) { parent_scope = parent; } // Output this scope in readable form to a stream. friend std::ostream &operator<<(std::ostream &os, MlEnvironment const &v); private: // The definitions in the scope. std::map defs; MlEnvironment *parent_scope; }; // An exception thrown by the lisp class MlError : public std::exception { public: MlError() = delete; // Create an error with the value that caused the error, // the scope where the error was found, and the message. MlError(const MlValue &v, MlEnvironment const &env, const char *msg); // Copy constructor is needed to prevent double frees MlError(MlError const &other); ~MlError(); // Get the printable error description. std::string description() const; private: MlValue *cause; MlEnvironment env; const char *msg; }; // The type for a builtin function, which takes a list of values, // and the environment to run the function in. typedef MlValue (*Builtin)(std::vector, MlEnvironment &); class MlValue { public: // Constructs a nil value MlValue(); // Constructs an integer MlValue(long i); // Constructs a floating point value MlValue(double f); // Constructs a bool value MlValue(bool b); // Constructs a list MlValue(const std::vector &list); // Construct a quoted value static MlValue quote(const MlValue "ed); // Construct an atom static MlValue atom(const std::string &s); // Construct a string static MlValue string(const std::string &s); // Construct a nil static MlValue nil(); // Construct a lambda function MlValue(const std::vector ¶ms, MlValue ret, MlEnvironment const &env); // Construct a builtin function MlValue(const std::string &name, Builtin b); std::vector get_used_atoms(); // Apply this as a function to a list of arguments in a given environment. MlValue apply(std::vector args, MlEnvironment &env); // Evaluate this value as lisp code. MlValue eval(MlEnvironment &env); bool is_builtin() const; bool is_number() const; bool is_string() const; // Get the boolean value of this value. bool as_bool() const; // Get this item's integer value long as_int() const; // Get this item's floating point value double as_float() const; // Get this item's string value std::string as_string() const; // Get this item's atom value std::string as_atom() const; // Get this item's list value std::vector as_list() const; // Push an item to the end of this list void push(MlValue val); // Push an item from the end of this list MlValue pop(); // Cast this to an integer value MlValue cast_to_int() const; // Cast this to a floating point value MlValue cast_to_float() const; // Cast this to a string MlValue cast_to_string() const; bool operator==(MlValue other) const; bool operator!=(const MlValue &other) const; bool operator>=(const MlValue &other) const; bool operator<=(const MlValue &other) const; bool operator>(const MlValue &other) const; bool operator<(const MlValue &other) const; // This function adds two lisp values, and returns the lisp value result. MlValue operator+(const MlValue &other) const; // This function subtracts two lisp values, and returns the lisp value result. MlValue operator-(const MlValue &other) const; // This function multiplies two lisp values, and returns the lisp value result. MlValue operator*(const MlValue &other) const; // This function divides two lisp values, and returns the lisp value result. MlValue operator/(const MlValue &other) const; // This function finds the remainder of two lisp values, and returns the lisp value result. MlValue operator%(const MlValue &other) const; // Get the name of the type of this value std::string get_type_name() const; std::string display() const; std::string debug() const; friend std::ostream &operator<<(std::ostream &os, MlValue const &v); private: enum { QUOTE, ATOM, INT, FLOAT, LIST, STRING, LAMBDA, BUILTIN, NIL } type; union { long i; double f; Builtin b; } stack_data; std::string str; std::vector list; MlEnvironment lambda_scope; };