-
Notifications
You must be signed in to change notification settings - Fork 0
/
4.lisp
26 lines (18 loc) · 62.1 KB
/
4.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
(defun comment? (cond) (if cond "//" ""))
(defun not (cond) (if cond 0 1))
(defun add-escapes (s)
(replace (replace (replace (replace s "\\" "\\\\") "\t" "\\t") "\n" "\\n") "\"" "\\\"")
)
(defun compile (has-libm? use-std? code)
(+
"/// A microlisp named Wisp, by Adam McDaniel\n\n////////////////////////////////////////////////////////////////////////////////\n/// LANGUAGE OPTIONS ///////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n// Comment this define out to drop support for libm functions\n" (comment? (not has-libm?)) "#define HAS_LIBM\n#ifdef HAS_LIBM\n#include <cmath>\n#else\n#define NO_LIBM_SUPPORT \"no libm support\"\n#endif\n\n\n// Comment this define out to drop support for standard library functions.\n// This allows the program to run without a runtime.\n" (comment? (not use-std?)) "#define USE_STD\n#ifdef USE_STD\n#include <cstdlib>\n#include <iostream>\n#include <fstream>\n#include <ctime>\n\nstd::string read_file_contents(std::string filename) {\n std::ifstream f;\n f.open(filename.c_str());\n if (!f)\n throw std::runtime_error(\"could not open file\");\n\n f.seekg(0, std::ios::end);\n std::string contents;\n contents.reserve(f.tellg());\n f.seekg(0, std::ios::beg);\n contents.assign(std::istreambuf_iterator<char>(f),\n std::istreambuf_iterator<char>());\n f.close();\n\n return contents;\n}\n\n#else\n#define NO_STD \"no standard library support\"\n#endif\n\n\n////////////////////////////////////////////////////////////////////////////////\n/// REQUIRED INCLUDES //////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n#include <map>\n#include <string>\n#include <vector>\n#include <sstream>\n#include <exception>\n\n////////////////////////////////////////////////////////////////////////////////\n/// ERROR MESSAGES /////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n#define TOO_FEW_ARGS \"too few arguments to function\"\n#define TOO_MANY_ARGS \"too many arguments to function\"\n#define INVALID_ARGUMENT \"invalid argument\"\n#define MISMATCHED_TYPES \"mismatched types\"\n#define CALL_NON_FUNCTION \"called non-function\"\n#define UNKNOWN_ERROR \"unknown exception\"\n#define INVALID_LAMBDA \"invalid lambda\"\n#define INVALID_BIN_OP \"invalid binary operation\"\n#define INVALID_ORDER \"cannot order expression\"\n#define BAD_CAST \"cannot cast\"\n#define ATOM_NOT_DEFINED \"atom not defined\"\n#define EVAL_EMPTY_LIST \"evaluated empty list\"\n#define INTERNAL_ERROR \"interal virtual machine error\"\n#define INDEX_OUT_OF_RANGE \"index out of range\"\n#define MALFORMED_PROGRAM \"malformed program\"\n\n////////////////////////////////////////////////////////////////////////////////\n/// TYPE NAMES /////////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n#define STRING_TYPE \"string\"\n#define INT_TYPE \"int\"\n#define FLOAT_TYPE \"float\"\n#define UNIT_TYPE \"unit\"\n#define FUNCTION_TYPE \"function\"\n#define ATOM_TYPE \"atom\"\n#define QUOTE_TYPE \"quote\"\n#define LIST_TYPE \"list\"\n\n////////////////////////////////////////////////////////////////////////////////\n/// HELPER FUNCTIONS ///////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n// Convert an object to a string using a stringstream conveniently\n#define to_string( x ) static_cast<std::ostringstream&>((std::ostringstream() << std::dec << x )).str()\n\n// Replace a substring with a replacement string in a source string\nvoid replace_substring(std::string &src, std::string substr, std::string replacement) {\n size_t i=0;\n for (i=src.find(substr, i); i!=std::string::npos; i=src.find(substr, i)) {\n src.replace(i, substr.size(), replacement);\n i += replacement.size();\n }\n}\n\n// Is this character a valid lisp symbol character\nbool is_symbol(char ch) {\n return (isalpha(ch) || ispunct(ch)) && ch != '(' && ch != ')' && ch != '\"' && ch != '\\'';\n}\n\n////////////////////////////////////////////////////////////////////////////////\n/// LISP CONSTRUCTS ////////////////////////////////////////////////////////////\n////////////////////////////////////////////////////////////////////////////////\n\n// Forward declaration for Environment class definition\nclass Value;\n\n\n// An instance of a function's scope.\nclass Environment {\npublic:\n // Default constructor\n Environment() : parent_scope(NULL) {}\n\n // Does this environment, or its parent environment,\n // have this atom in scope?\n // This is only used to determine which atoms to capture when\n // creating a lambda function.\n bool has(std::string name) const;\n // Get the value associated with this name in this scope\n Value get(std::string name) const;\n // Set the value associated with this name in this scope\n void set(std::string name, Value value);\n\n void combine(Environment const &other);\n\n void set_parent_scope(Environment *parent) {\n parent_scope = parent;\n }\n \n // Output this scope in readable form to a stream.\n friend std::ostream &operator<<(std::ostream &os, Environment const &v);\nprivate:\n\n // The definitions in the scope.\n std::map<std::string, Value> defs;\n Environment *parent_scope;\n};\n\n\n// An exception thrown by the lisp\nclass Error {\npublic:\n // Create an error with the value that caused the error,\n // the scope where the error was found, and the message.\n Error(Value v, Environment const &env, const char *msg);\n // Copy constructor is needed to prevent double frees\n Error(Error const &other);\n ~Error();\n\n // Get the printable error description.\n std::string description();\nprivate:\n Value *cause;\n Environment env;\n const char *msg;\n};\n\n// The type for a builtin function, which takes a list of values,\n// and the environment to run the function in.\ntypedef Value (*Builtin)(std::vector<Value>, Environment &);\n\nclass Value {\npublic:\n ////////////////////////////////////////////////////////////////////////////////\n /// CONSTRUCTORS ///////////////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n // Constructs a unit value\n Value() : type(UNIT) {}\n\n // Constructs an integer\n Value(int i) : type(INT) { stack_data.i = i; }\n // Constructs a floating point value\n Value(double f) : type(FLOAT) { stack_data.f = f; }\n // Constructs a list\n Value(std::vector<Value> list) : type(LIST), list(list) {}\n\n // Construct a quoted value\n static Value quote(Value quoted) {\n Value result;\n result.type = QUOTE;\n\n // The first position in the list is\n // used to store the quoted expression.\n result.list.push_back(quoted);\n return result;\n }\n\n // Construct an atom\n static Value atom(std::string s) {\n Value result;\n result.type = ATOM;\n\n // We use the `str` member to store the atom.\n result.str = s;\n return result;\n }\n\n // Construct a string\n static Value string(std::string s) {\n Value result;\n result.type = STRING;\n\n // We use the `str` member to store the string.\n result.str = s;\n return result;\n }\n\n // Construct a lambda function\n Value(std::vector<Value> params, Value ret, Environment const &env) : type(LAMBDA) {\n // We store the params and the result in the list member\n // instead of having dedicated members. This is to save memory.\n list.push_back(Value(params));\n list.push_back(ret);\n\n // Lambdas capture only variables that they know they will use.\n std::vector<std::string> used_atoms = ret.get_used_atoms();\n for (size_t i=0; i<used_atoms.size(); i++) {\n // If the environment has a symbol that this lambda uses, capture it.\n if (env.has(used_atoms[i]))\n lambda_scope.set(used_atoms[i], env.get(used_atoms[i]));\n }\n }\n\n // Construct a builtin function\n Value(std::string name, Builtin b) : type(BUILTIN) {\n // Store the name of the builtin function in the str member\n // to save memory, and use the builtin function slot in the union\n // to store the function pointer.\n str = name;\n stack_data.b = b;\n }\n\n ////////////////////////////////////////////////////////////////////////////////\n /// C++ INTEROP METHODS ////////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n // Get all of the atoms used in a given Value\n std::vector<std::string> get_used_atoms() {\n std::vector<std::string> result, tmp;\n switch (type) {\n case QUOTE:\n // The data for a quote is stored in the\n // first slot of the list member.\n return list[0].get_used_atoms();\n case ATOM:\n // If this is an atom, add it to the list\n // of used atoms in this expression.\n result.push_back(as_atom());\n return result;\n case LAMBDA:\n // If this is a lambda, get the list of used atoms in the body\n // of the expression.\n return list[1].get_used_atoms();\n case LIST:\n // If this is a list, add each of the atoms used in all\n // of the elements in the list.\n for (size_t i=0; i<list.size(); i++) {\n // Get the atoms used in the element\n tmp = list[i].get_used_atoms();\n // Add the used atoms to the current list of used atoms\n result.insert(result.end(), tmp.begin(), tmp.end());\n }\n return result;\n default:\n return result;\n }\n }\n\n // Is this a builtin function?\n bool is_builtin() {\n return type == BUILTIN;\n }\n\n // Apply this as a function to a list of arguments in a given environment.\n Value apply(std::vector<Value> args, Environment &env);\n // Evaluate this value as lisp code.\n Value eval(Environment &env);\n\n bool is_number() const {\n return type == INT || type == FLOAT;\n }\n\n // Get the \"truthy\" boolean value of this value.\n bool as_bool() const {\n return *this != Value(0);\n }\n\n // Get this item's integer value\n int as_int() const {\n return cast_to_int().stack_data.i;\n }\n\n // Get this item's floating point value\n double as_float() const {\n return cast_to_int().stack_data.f;\n }\n\n // Get this item's string value\n std::string as_string() const {\n // If this item is not a string, throw a cast error.\n if (type != STRING)\n throw Error(*this, Environment(), BAD_CAST);\n return str;\n }\n\n // Get this item's atom value\n std::string as_atom() const {\n // If this item is not an atom, throw a cast error.\n if (type != ATOM)\n throw Error(*this, Environment(), BAD_CAST);\n return str;\n }\n\n // Get this item's list value\n std::vector<Value> as_list() const {\n // If this item is not a list, throw a cast error.\n if (type != LIST)\n throw Error(*this, Environment(), BAD_CAST);\n return list;\n }\n\n // Push an item to the end of this list\n void push(Value val) {\n // If this item is not a list, you cannot push to it.\n // Throw an error.\n if (type != LIST)\n throw Error(*this, Environment(), MISMATCHED_TYPES);\n \n list.push_back(val);\n }\n\n // Push an item from the end of this list\n Value pop() {\n // If this item is not a list, you cannot pop from it.\n // Throw an error.\n if (type != LIST)\n throw Error(*this, Environment(), MISMATCHED_TYPES);\n \n // Remember the last item in the list\n Value result = list[list.size()-1];\n // Remove it from this instance\n list.pop_back();\n // Return the remembered value\n return result;\n }\n\n ////////////////////////////////////////////////////////////////////////////////\n /// TYPECASTING METHODS ////////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n // Cast this to an integer value\n Value cast_to_int() const {\n switch (type) {\n case INT: return *this;\n case FLOAT: return Value(int(stack_data.f));\n // Only ints and floats can be cast to an int\n default:\n throw Error(*this, Environment(), BAD_CAST);\n }\n }\n\n // Cast this to a floating point value\n Value cast_to_float() const {\n switch (type) {\n case FLOAT: return *this;\n case INT: return Value(float(stack_data.i));\n // Only ints and floats can be cast to a float\n default:\n throw Error(*this, Environment(), BAD_CAST);\n }\n }\n\n ////////////////////////////////////////////////////////////////////////////////\n /// COMPARISON OPERATIONS //////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n bool operator==(Value other) const {\n // If either of these values are floats, promote the\n // other to a float, and then compare for equality.\n if (type == FLOAT && other.type == INT) return *this == other.cast_to_float();\n else if (type == INT && other.type == FLOAT) return this->cast_to_float() == other;\n // If the values types aren't equal, then they cannot be equal.\n else if (type != other.type) return false;\n\n switch (type) {\n case FLOAT:\n return stack_data.f == other.stack_data.f;\n case INT:\n return stack_data.i == other.stack_data.i;\n case BUILTIN:\n return stack_data.b == other.stack_data.b;\n case STRING:\n case ATOM:\n // Both atoms and strings store their\n // data in the str member.\n return str == other.str;\n case LAMBDA:\n case LIST:\n // Both lambdas and lists store their\n // data in the list member.\n return list == other.list;\n case QUOTE:\n // The values for quotes are stored in the\n // first slot of the list member.\n return list[0] == other.list[0];\n default:\n return true;\n }\n }\n \n bool operator!=(Value other) const {\n return !(*this == other);\n }\n\n // bool operator<(Value other) const {\n // if (other.type != FLOAT && other.type != INT)\n // throw Error(*this, Environment(), INVALID_BIN_OP);\n\n // switch (type) {\n // case FLOAT:\n // return stack_data.f < other.cast_to_float().stack_data.f;\n // case INT:\n // if (other.type == FLOAT)\n // return cast_to_float().stack_data.f < other.stack_data.f;\n // else return stack_data.i < other.stack_data.i;\n // default:\n // throw Error(*this, Environment(), INVALID_ORDER);\n // }\n // }\n \n ////////////////////////////////////////////////////////////////////////////////\n /// ORDERING OPERATIONS ////////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n bool operator>=(Value other) const {\n return !(*this < other);\n }\n \n bool operator<=(Value other) const {\n return (*this == other) || (*this < other);\n }\n \n bool operator>(Value other) const {\n return !(*this <= other);\n }\n\n bool operator<(Value other) const {\n // Other type must be a float or an int\n if (other.type != FLOAT && other.type != INT)\n throw Error(*this, Environment(), INVALID_BIN_OP);\n\n switch (type) {\n case FLOAT:\n // If this is a float, promote the other value to a float and compare.\n return stack_data.f < other.cast_to_float().stack_data.f;\n case INT:\n // If the other value is a float, promote this value to a float and compare.\n if (other.type == FLOAT)\n return cast_to_float().stack_data.f < other.stack_data.f;\n // Otherwise compare the integer values\n else return stack_data.i < other.stack_data.i;\n default:\n // Only allow comparisons between integers and floats\n throw Error(*this, Environment(), INVALID_ORDER);\n }\n }\n \n ////////////////////////////////////////////////////////////////////////////////\n /// ARITHMETIC OPERATIONS //////////////////////////////////////////////////////\n ////////////////////////////////////////////////////////////////////////////////\n\n // This function adds two lisp values, and returns the lisp value result.\n Value operator+(Value other) const {\n // If the other value's type is the unit type,\n // don't even bother continuing.\n // Unit types consume all arithmetic operations.\n if (other.type == UNIT) return other;\n\n // Other type must be a float or an int\n if ((is_number() || other.is_number()) &&\n !(is_number() && other.is_number()))\n throw Error(*this, Environment(), INVALID_BIN_OP);\n\n switch (type) {\n case FLOAT:\n // If one is a float, promote the other by default and do\n // float addition.\n return Value(stack_data.f + other.cast_to_float().stack_data.f);\n case INT:\n // If the other type is a float, go ahead and promote this expression\n // before continuing with the addition.\n if (other.type == FLOAT)\n return Value(cast_to_float() + other.stack_data.f);\n // Otherwise, do integer addition.\n else return Value(stack_data.i + other.stack_data.i);\n case STRING:\n // If the other value is also a string, do the concat\n if (other.type == STRING)\n return Value::string(str + other.str);\n // We throw an error if we try to concat anything of non-string type\n else throw Error(*this, Environment(), INVALID_BIN_OP);\n case LIST:\n // If the other value is also a list, do the concat\n if (other.type == LIST) {\n // Maintain the value that will be returned\n Value result = *this;\n // Add each item in the other list to the end of this list\n for (size_t i=0; i<other.list.size(); i++)\n result.push(other.list[i]);\n return result;\n \n } else throw Error(*this, Environment(), INVALID_BIN_OP);\n case UNIT:\n return *this;\n default:\n throw Error(*this, Environment(), INVALID_BIN_OP);\n }\n }\n\n // This function subtracts two lisp values, and returns the lisp value result.\n Value operator-(Value other) const {\n // If the other value's type is the unit type,\n // don't even bother continuing.\n // Unit types consume all arithmetic operations.\n if (other.type == UNIT) return other;\n\n // Other type must be a float or an int\n if (other.type != FLOAT && other.type != INT)\n throw Error(*this, Environment(), INVALID_BIN_OP);\n\n switch (type) {\n case FLOAT:\n // If one is a float, promote the other by default and do\n // float subtraction.\n return Value(stack_data.f - other.cast_to_float().stack_data.f);\n case INT:\n // If the other type is a float, go ahead and promote this expression\n // before continuing with the subtraction\n if (other.type == FLOAT)\n return Value(cast_to_float().stack_data.f - other.stack_data.f);\n // Otherwise, do integer subtraction.\n else return Value(stack_data.i - other.stack_data.i);\n case UNIT:\n // Unit types consume all arithmetic operations.\n return *this;\n default:\n // This operation was done on an unsupported type\n throw Error(*this, Environment(), INVALID_BIN_OP);\n }\n }\n\n // This function multiplies two lisp values, and returns the lisp value result.\n Value operator*(Value other) const {\n // If the other value's type is the unit type,\n // don't even bother continuing.\n // Unit types consume all arithmetic operations.\n if (other.type == UNIT) return other;\n\n // Other type must be a float or an int\n if (other.type != FLOAT && other.type != INT)\n throw Error(*this, Environment(), INVALID_BIN_OP);\n \n switch (type) {\n case FLOAT:\n return Value(stack_data.f * other.cast_to_float().stack_data.f);\n case INT:\n // If the other type is a float, go ahead and promote this expression\n // before continuing with the product\n if (other.type == FLOAT)\n return Value(cast_to_float().stack_data.f * other.stack_data.f);\n // Otherwise, do integer multiplication.\n else return Value(stack_data.i * other.stack_data.i);\n case UNIT:\n // Unit types consume all arithmetic operations.\n return *this;\n default:\n // This operation was done on an unsupported type\n throw Error(*this, Environment(), INVALID_BIN_OP);\n }\n }\n\n // This function divides two lisp values, and returns the lisp value result.\n Value operator/(Value other) const {\n // If the other value's type is the unit type,\n // don't even bother continuing.\n // Unit types consume all arithmetic operations.\n if (other.type == UNIT) return other;\n\n // Other type must be a float or an int\n if (other.type != FLOAT && other.type != INT)\n throw Error(*this, Environment(), INVALID_BIN_OP);\n\n switch (type) {\n case FLOAT:\n return Value(stack_data.f / other.cast_to_float().stack_data.f);\n case INT:\n // If the other type is a float, go ahead and promote this expression\n // before continuing with the product\n if (other.type == FLOAT)\n return Value(cast_to_float().stack_data.f / other.stack_data.f);\n // Otherwise, do integer multiplication.\n else return Value(stack_data.i / other.stack_data.i);\n case UNIT:\n // Unit types consume all arithmetic operations.\n return *this;\n default:\n // This operation was done on an unsupported type\n throw Error(*this, Environment(), INVALID_BIN_OP);\n }\n }\n\n // This function finds the remainder of two lisp values, and returns the lisp value result.\n Value operator%(Value other) const {\n // If the other value's type is the unit type,\n // don't even bother continuing.\n // Unit types consume all arithmetic operations.\n if (other.type == UNIT) return other;\n\n // Other type must be a float or an int\n if (other.type != FLOAT && other.type != INT)\n throw Error(*this, Environment(), INVALID_BIN_OP);\n \n switch (type) {\n // If we support libm, we can find the remainder of floating point values.\n #ifdef HAS_LIBM\n case FLOAT:\n return Value(fmod(stack_data.f, other.cast_to_float().stack_data.f));\n case INT:\n if (other.type == FLOAT)\n return Value(fmod(cast_to_float().stack_data.f, other.stack_data.f));\n else return Value(stack_data.i % other.stack_data.i);\n\n #else\n case INT:\n // If we do not support libm, we have to throw errors for floating point values.\n if (other.type != INT)\n throw Error(other, Environment(), NO_LIBM_SUPPORT);\n return Value(stack_data.i % other.stack_data.i);\n #endif\n\n case UNIT:\n // Unit types consume all arithmetic operations.\n return *this;\n default:\n // This operation was done on an unsupported type\n throw Error(*this, Environment(), INVALID_BIN_OP);\n }\n }\n\n // Get the name of the type of this value\n std::string get_type_name() {\n switch (type) {\n case QUOTE: return QUOTE_TYPE;\n case ATOM: return ATOM_TYPE;\n case INT: return INT_TYPE;\n case FLOAT: return FLOAT_TYPE;\n case LIST: return LIST_TYPE;\n case STRING: return STRING_TYPE;\n case BUILTIN:\n case LAMBDA:\n // Instead of differentiating between\n // lambda and builtin types, we group them together.\n // This is because they are both callable.\n return FUNCTION_TYPE;\n case UNIT:\n return UNIT_TYPE;\n default:\n // We don't know the name of this type.\n // This isn't the users fault, this is just unhandled.\n // This should never be reached.\n throw Error(*this, Environment(), INTERNAL_ERROR);\n }\n }\n\n std::string display() const {\n std::string result;\n switch (type) {\n case QUOTE:\n return \"'\" + list[0].debug();\n case ATOM:\n return str;\n case INT:\n return to_string(stack_data.i);\n case FLOAT:\n return to_string(stack_data.f);\n case STRING:\n return str;\n case LAMBDA:\n for (size_t i=0; i<list.size(); i++) {\n result += list[i].debug();\n if (i < list.size()-1) result += \" \";\n }\n return \"(lambda \" + result + \")\";\n case LIST:\n for (size_t i=0; i<list.size(); i++) {\n result += list[i].debug();\n if (i < list.size()-1) result += \" \";\n }\n return \"(\" + result + \")\";\n case BUILTIN:\n return \"<\" + str + \" at \" + to_string(long(stack_data.b)) + \">\";\n case UNIT:\n return \"@\";\n default:\n // We don't know how to display whatever type this is.\n // This isn't the users fault, this is just unhandled.\n // This should never be reached.\n throw Error(*this, Environment(), INTERNAL_ERROR);\n }\n }\n\n std::string debug() const {\n std::string result;\n switch (type) {\n case QUOTE:\n return \"'\" + list[0].debug();\n case ATOM:\n return str;\n case INT:\n return to_string(stack_data.i);\n case FLOAT:\n return to_string(stack_data.f);\n case STRING:\n for (size_t i=0; i<str.length(); i++) {\n if (str[i] == '\"') result += \"\\\\\\\"\";\n else result.push_back(str[i]);\n }\n return \"\\\"\" + result + \"\\\"\";\n case LAMBDA:\n for (size_t i=0; i<list.size(); i++) {\n result += list[i].debug();\n if (i < list.size()-1) result += \" \";\n }\n return \"(lambda \" + result + \")\";\n case LIST:\n for (size_t i=0; i<list.size(); i++) {\n result += list[i].debug();\n if (i < list.size()-1) result += \" \";\n }\n return \"(\" + result + \")\";\n case BUILTIN:\n return \"<\" + str + \" at \" + to_string(long(stack_data.b)) + \">\";\n case UNIT:\n return \"@\";\n default:\n // We don't know how to debug whatever type this is.\n // This isn't the users fault, this is just unhandled.\n // This should never be reached.\n throw Error(*this, Environment(), INTERNAL_ERROR);\n }\n }\n\n friend std::ostream &operator<<(std::ostream &os, Value const &v) {\n return os << v.display();\n }\n\nprivate:\n enum {\n QUOTE,\n ATOM,\n INT,\n FLOAT,\n LIST,\n STRING,\n LAMBDA,\n BUILTIN,\n UNIT\n } type;\n\n union {\n int i;\n double f;\n Builtin b;\n } stack_data;\n\n std::string str;\n std::vector<Value> list;\n Environment lambda_scope;\n};\n\nError::Error(Value v, Environment const &env, const char *msg) : env(env), msg(msg) {\n cause = new Value;\n *cause = v;\n}\n\nError::Error(Error const &other) : env(other.env), msg(other.msg) {\n cause = new Value(*other.cause);\n}\n\nError::~Error() {\n delete cause;\n}\n\nstd::string Error::description() {\n return \"error: the expression `\" + cause->debug() + \"` failed in scope \" + to_string(env) + \" with message \\\"\" + msg + \"\\\"\";\n}\n\nvoid Environment::combine(Environment const &other) {\n // Normally, I would use the `insert` method of the `map` class,\n // but it doesn't overwrite previously declared values for keys.\n std::map<std::string, Value>::const_iterator itr = other.defs.begin();\n for (; itr!=other.defs.end(); itr++) {\n // Iterate through the keys and assign each value.\n defs[itr->first] = itr->second;\n }\n}\n\nstd::ostream &operator<<(std::ostream &os, Environment const &e) {\n std::map<std::string, Value>::const_iterator itr = e.defs.begin();\n os << \"{ \";\n for (; itr != e.defs.end(); itr++) {\n os << '\\'' << itr->first << \"' : \" << itr->second.debug() << \", \";\n }\n return os << \"}\";\n}\n\nvoid Environment::set(std::string name, Value value) {\n defs[name] = value;\n}\n\n\nValue Value::apply(std::vector<Value> args, Environment &env) {\n Environment e;\n std::vector<Value> params;\n switch (type) {\n case LAMBDA:\n // Get the list of parameter atoms\n params = list[0].list;\n if (params.size() != args.size())\n throw Error(Value(args), env, args.size() > params.size()?\n TOO_MANY_ARGS : TOO_FEW_ARGS\n );\n\n // Get the captured scope from the lambda\n e = lambda_scope;\n // And make this scope the parent scope\n e.set_parent_scope(&env);\n\n // Iterate through the list of parameters and\n // insert the arguments into the scope.\n for (size_t i=0; i<params.size(); i++) {\n if (params[i].type != ATOM) \n throw Error(*this, env, INVALID_LAMBDA);\n // Set the parameter name into the scope.\n e.set(params[i].str, args[i]);\n }\n\n // Evaluate the function body with the function scope\n return list[1].eval(e);\n case BUILTIN:\n // Here, we call the builtin function with the current scope.\n // This allows us to write special forms without syntactic sugar.\n // For functions that are not special forms, we just evaluate\n // the arguments before we run the function.\n return (stack_data.b)(args, env);\n default:\n // We can only call lambdas and builtins\n throw Error(*this, env, CALL_NON_FUNCTION);\n }\n}\n\n\nValue Value::eval(Environment &env) {\n std::vector<Value> args;\n Value function;\n Environment e;\n switch (type) {\n case QUOTE:\n return list[0];\n case ATOM:\n return env.get(str);\n case LIST:\n if (list.size() < 1)\n throw Error(*this, env, EVAL_EMPTY_LIST);\n\n args = std::vector<Value>(list.begin() + 1, list.end());\n \n // Only evaluate our arguments if it's not builtin!\n // Builtin functions can be special forms, so we\n // leave them to evaluate their arguments.\n function = list[0].eval(env);\n\n if (!function.is_builtin())\n for (size_t i=0; i<args.size(); i++)\n args[i] = args[i].eval(env);\n\n return function.apply(\n args,\n env\n );\n\n default:\n return *this;\n }\n}\n\nvoid skip_whitespace(std::string &s, int &ptr) {\n while (isspace(s[ptr])) { ptr++; }\n}\n\nValue parse(std::string &s, int &ptr) {\n skip_whitespace(s, ptr);\n\n while (s[ptr] == ';') {\n // If this is a comment\n int save_ptr = ptr;\n while (s[save_ptr] != '\\n' && save_ptr < int(s.length())) { save_ptr++; }\n s.erase(ptr, save_ptr - ptr);\n skip_whitespace(s, ptr);\n\n if (s.substr(ptr, s.length()-ptr-1) == \"\")\n return Value();\n }\n\n\n if (s == \"\") {\n return Value();\n } else if (s[ptr] == '\\'') {\n // If this is a quote\n ptr++;\n return Value::quote(parse(s, ptr));\n\n } else if (s[ptr] == '(') {\n // If this is a list\n skip_whitespace(s, ++ptr);\n\n Value result = Value(std::vector<Value>());\n\n while (s[ptr] != ')')\n result.push(parse(s, ptr));\n \n skip_whitespace(s, ++ptr);\n return result;\n \n } else if (isdigit(s[ptr]) || (s[ptr] == '-' && isdigit(s[ptr + 1]))) {\n // If this is a number\n bool negate = s[ptr] == '-';\n if (negate) ptr++;\n \n int save_ptr = ptr;\n while (isdigit(s[ptr]) || s[ptr] == '.') ptr++;\n std::string n = s.substr(save_ptr, ptr);\n skip_whitespace(s, ptr);\n \n if (n.find('.') != std::string::npos)\n return Value((negate? -1 : 1) * atof(n.c_str()));\n else return Value((negate? -1 : 1) * atoi(n.c_str()));\n\n } else if (s[ptr] == '\\\"') {\n // If this is a string\n int n = 1;\n while (s[ptr + n] != '\\\"') {\n if (ptr + n >= int(s.length()))\n throw std::runtime_error(MALFORMED_PROGRAM);\n \n if (s[ptr + n] == '\\\\') n++;\n n++;\n }\n\n std::string x = s.substr(ptr+1, n-1);\n ptr += n+1;\n skip_whitespace(s, ptr);\n\n for (size_t i=0; i<x.size(); i++) {\n if (x[i] == '\\\\' && x[i+1] == '\\\\')\n x.replace(i, 2, \"\\\\\");\n else if (x[i] == '\\\\' && x[i+1] == '\"')\n x.replace(i, 2, \"\\\"\");\n else if (x[i] == '\\\\' && x[i+1] == 'n')\n x.replace(i, 2, \"\\n\");\n else if (x[i] == '\\\\' && x[i+1] == 't')\n x.replace(i, 2, \"\\t\");\n }\n\n return Value::string(x);\n } else if (s[ptr] == '@') {\n ptr++;\n skip_whitespace(s, ptr);\n return Value();\n\n } else if (is_symbol(s[ptr])) {\n // If this is a string\n int n = 0;\n while (is_symbol(s[ptr + n])) {\n n++;\n }\n\n std::string x = s.substr(ptr, n);\n ptr += n;\n skip_whitespace(s, ptr);\n return Value::atom(x);\n } else {\n throw std::runtime_error(MALFORMED_PROGRAM);\n }\n}\n\nstd::vector<Value> parse(std::string s) {\n int i=0, last_i=-1;\n std::vector<Value> result;\n while (last_i != i && i <= int(s.length()-1)) {\n last_i = i;\n result.push_back(parse(s, i));\n }\n\n if (i < int(s.length()))\n throw std::runtime_error(MALFORMED_PROGRAM);\n\n return result;\n}\n\nValue run(std::string code, Environment &env) {\n std::vector<Value> parsed = parse(code);\n for (size_t i=0; i<parsed.size()-1; i++)\n parsed[i].eval(env);\n\n return parsed[parsed.size()-1].eval(env);\n}\n\nnamespace builtin {\n void eval_args(std::vector<Value> &args, Environment &env) {\n for (size_t i=0; i<args.size(); i++)\n args[i] = args[i].eval(env);\n }\n\n Value lambda(std::vector<Value> args, Environment &env) {\n if (args.size() < 2)\n throw Error(Value(\"lambda\", lambda), env, TOO_FEW_ARGS);\n\n if (args[0].get_type_name() != LIST_TYPE)\n throw Error(Value(\"lambda\", lambda), env, INVALID_LAMBDA);\n\n return Value(args[0].as_list(), args[1], env);\n }\n\n Value if_then_else(std::vector<Value> args, Environment &env) {\n if (args.size() != 3)\n throw Error(Value(\"if\", if_then_else), env, args.size() > 3? TOO_MANY_ARGS : TOO_FEW_ARGS);\n if (args[0].eval(env).as_bool())\n return args[1].eval(env);\n else return args[2].eval(env);\n }\n\n Value define(std::vector<Value> args, Environment &env) {\n if (args.size() != 2)\n throw Error(Value(\"define\", define), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n \n Value result = args[1].eval(env);\n env.set(args[0].display(), result);\n return result;\n }\n\n Value defun(std::vector<Value> args, Environment &env) {\n if (args.size() != 3)\n throw Error(Value(\"defun\", defun), env, args.size() > 3? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n if (args[1].get_type_name() != LIST_TYPE)\n throw Error(Value(\"defun\", defun), env, INVALID_LAMBDA);\n\n Value f = Value(args[1].as_list(), args[2], env);\n env.set(args[0].display(), f);\n return f;\n }\n\n Value while_loop(std::vector<Value> args, Environment &env) {\n Value acc;\n while (args[0].eval(env).as_bool()) {\n for (size_t i=1; i<args.size()-1; i++)\n args[i].eval(env);\n acc = args[args.size()-1].eval(env);\n }\n return acc;\n }\n\n Value for_loop(std::vector<Value> args, Environment &env) {\n Value acc;\n std::vector<Value> list = args[1].eval(env).as_list();\n\n for (size_t i=0; i<list.size(); i++) {\n env.set(args[0].as_atom(), list[i]);\n\n for (size_t j=1; j<args.size()-1; j++)\n args[j].eval(env);\n acc = args[args.size()-1].eval(env);\n }\n\n return acc;\n }\n\n Value do_block(std::vector<Value> args, Environment &env) {\n Value acc;\n for (size_t i=0; i<args.size(); i++)\n acc = args[i].eval(env);\n return acc;\n }\n\n Value scope(std::vector<Value> args, Environment &env) {\n Environment e = env;\n Value acc;\n for (size_t i=0; i<args.size(); i++)\n acc = args[i].eval(e);\n return acc;\n }\n\n Value quote(std::vector<Value> args, Environment &env) {\n std::vector<Value> v;\n for (size_t i=0; i<args.size(); i++)\n v.push_back(args[i]);\n return Value(v);\n }\n\n #ifdef USE_STD\n Value exit(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n std::exit(args.size() < 1? 0 : args[0].cast_to_int().as_int());\n return Value();\n }\n\n Value print(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() < 1)\n throw Error(Value(\"print\", print), env, TOO_FEW_ARGS);\n\n Value acc;\n for (size_t i=0; i<args.size(); i++) {\n acc = args[i];\n std::cout << acc.display();\n if (i < args.size() - 1)\n std::cout << \" \";\n }\n std::cout << std::endl;\n return acc;\n }\n\n Value input(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() > 1)\n throw Error(Value(\"input\", input), env, TOO_MANY_ARGS);\n\n if (!args.empty())\n std::cout << args[0];\n\n std::string s;\n std::getline(std::cin, s);\n return Value::string(s);\n }\n\n Value random(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"random\", random), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n int low = args[0].as_int(), high = args[1].as_int();\n return Value(rand()%(high-low+1) + low);\n }\n\n Value read_file(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"read-file\", read_file), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n // return Value::string(content);\n return Value::string(read_file_contents(args[0].as_string()));\n }\n\n Value write_file(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"write-file\", write_file), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::ofstream f;\n f.open(args[0].as_string().c_str());\n Value result = Value((f << args[1].as_string())? 1 : 0);\n f.close();\n return result;\n }\n\n Value include(std::vector<Value> args, Environment &env) {\n // Import is technically not a special form, it's more of a macro.\n // We can evaluate our arguments.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"include\", include), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n Environment e;\n Value result = run(read_file_contents(args[0].as_string()), e);\n env.combine(e);\n return result;\n }\n Value os_cmd(std::vector<Value> args, Environment &env) {\n // Import is technically not a special form, it's more of a macro.\n // We can evaluate our arguments.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"os-cmd\", os_cmd), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n return Value(system(args[0].as_string().c_str()));\n }\n\t#endif\n Value eval(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"eval\", eval), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n else return args[0].eval(env);\n }\n\n Value list(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n \n return Value(args);\n }\n\n Value sum(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n \n if (args.size() < 2)\n throw Error(Value(\"+\", sum), env, TOO_FEW_ARGS);\n \n Value acc = args[0];\n for (size_t i=1; i<args.size(); i++)\n acc = acc + args[i];\n return acc;\n }\n\n Value subtract(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"-\", subtract), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0] - args[1];\n }\n\n Value product(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() < 2)\n throw Error(Value(\"*\", product), env, TOO_FEW_ARGS);\n\n Value acc = args[0];\n for (size_t i=1; i<args.size(); i++)\n acc = acc * args[i];\n return acc;\n }\n\n Value divide(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"/\", divide), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0] / args[1];\n }\n\n Value remainder(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"%\", remainder), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0] % args[1];\n }\n\n Value eq(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"=\", eq), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] == args[1]));\n }\n\n Value neq(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"!=\", neq), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] != args[1]));\n }\n\n Value greater(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\">\", greater), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] > args[1]));\n }\n\n Value less(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"<\", less), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] < args[1]));\n }\n\n Value greater_eq(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\">=\", greater_eq), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] >= args[1]));\n }\n\n Value less_eq(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"<=\", less_eq), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return Value(int(args[0] <= args[1]));\n }\n\n Value get_type_name(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"type\", get_type_name), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n return Value::string(args[0].get_type_name());\n }\n\n\n Value cast_to_float(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(FLOAT_TYPE, cast_to_float), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0].cast_to_float();\n }\n\n Value cast_to_int(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(INT_TYPE, cast_to_int), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0].cast_to_int();\n }\n\n Value index(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"index\", index), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::vector<Value> list = args[0].as_list();\n int i = args[1].as_int();\n if (list.empty() || i >= list.size())\n throw Error(list, env, INDEX_OUT_OF_RANGE);\n\n return list[i];\n }\n\n Value insert(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 3)\n throw Error(Value(\"insert\", insert), env, args.size() > 3? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::vector<Value> list = args[0].as_list();\n int i = args[1].as_int();\n if (i > list.size())\n throw Error(list, env, INDEX_OUT_OF_RANGE);\n\n list.insert(list.begin() + args[1].as_int(), args[2]);\n return Value(list);\n }\n\n Value remove(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 2)\n throw Error(Value(\"remove\", remove), env, args.size() > 2? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::vector<Value> list = args[0].as_list();\n int i = args[1].as_int();\n if (list.empty() || i >= list.size())\n throw Error(list, env, INDEX_OUT_OF_RANGE);\n\n list.erase(list.begin() + i);\n return Value(list);\n }\n\n Value len(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"len\", len), env, args.size() > 1?\n TOO_MANY_ARGS : TOO_FEW_ARGS\n );\n \n return Value(int(args[0].as_list().size()));\n }\n\n Value push(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() == 0)\n throw Error(Value(\"push\", push), env, TOO_FEW_ARGS);\n for (size_t i=1; i<args.size(); i++)\n args[0].push(args[i]);\n return args[0];\n }\n\n Value pop(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"pop\", pop), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n return args[0].pop();\n }\n\n Value head(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"head\", head), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n std::vector<Value> list = args[0].as_list();\n if (list.empty())\n throw Error(Value(\"head\", head), env, INDEX_OUT_OF_RANGE);\n\n return list[0];\n }\n\n Value tail(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"tail\", tail), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::vector<Value> result, list = args[0].as_list();\n\n for (size_t i = 1; i<list.size(); i++)\n result.push_back(list[i]);\n \n return Value(result);\n }\n\n Value parse(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"parse\", parse), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n if (args[0].get_type_name() != STRING_TYPE)\n throw Error(args[0], env, INVALID_ARGUMENT);\n std::vector<Value> parsed = ::parse(args[0].as_string());\n\n // if (parsed.size() == 1)\n // return parsed[0];\n // else return Value(parsed);\n return Value(parsed);\n }\n\n Value replace(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 3)\n throw Error(Value(\"replace\", replace), env, args.size() > 3? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n std::string src = args[0].as_string();\n replace_substring(src, args[1].as_string(), args[2].as_string());\n return Value::string(src);\n }\n\n Value display(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"display\", display), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n return Value::string(args[0].display());\n }\n\n Value debug(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n if (args.size() != 1)\n throw Error(Value(\"debug\", debug), env, args.size() > 1? TOO_MANY_ARGS : TOO_FEW_ARGS);\n\n return Value::string(args[0].debug());\n }\n\n Value map_list(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n std::vector<Value> result, l=args[1].as_list(), tmp;\n for (size_t i=0; i<l.size(); i++) {\n tmp.push_back(l[i]);\n result.push_back(args[0].apply(tmp, env));\n tmp.clear();\n }\n return Value(result);\n }\n\n Value filter_list(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n std::vector<Value> result, l=args[1].as_list(), tmp;\n for (size_t i=0; i<l.size(); i++) {\n tmp.push_back(l[i]);\n if (args[0].apply(tmp, env).as_bool())\n result.push_back(l[i]);\n tmp.clear();\n }\n return Value(result);\n }\n\n Value reduce_list(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n std::vector<Value> l=args[2].as_list(), tmp;\n Value acc = args[1];\n for (size_t i=0; i<l.size(); i++) {\n tmp.push_back(acc);\n tmp.push_back(l[i]);\n acc = args[0].apply(tmp, env);\n tmp.clear();\n }\n return acc;\n }\n\n Value range(std::vector<Value> args, Environment &env) {\n // Is not a special form, so we can evaluate our args.\n eval_args(args, env);\n\n std::vector<Value> result;\n Value low = args[0], high = args[1];\n if (low.get_type_name() != INT_TYPE && low.get_type_name() != FLOAT_TYPE)\n throw Error(low, env, MISMATCHED_TYPES);\n if (high.get_type_name() != INT_TYPE && high.get_type_name() != FLOAT_TYPE)\n throw Error(high, env, MISMATCHED_TYPES);\n\n if (low >= high) return Value(result);\n\n while (low < high) {\n result.push_back(low);\n low = low + Value(1);\n }\n return Value(result);\n }\n}\n\nvoid repl(Environment &env) {\n#ifdef USE_STD\n std::string code;\n std::string input;\n Value tmp;\n std::vector<Value> parsed;\n while (true) {\n std::cout << \">>> \";\n std::getline(std::cin, input);\n if (input == \"!quit\" || input == \"!q\")\n break;\n else if (input == \"!env\" || input == \"!e\")\n std::cout << env << std::endl;\n else if (input == \"!export\" || input == \"!x\") {\n std::cout << \"File to export to: \";\n std::getline(std::cin, input);\n\n std::ofstream f;\n f.open(input.c_str(), std::ofstream::out);\n f << code;\n f.close();\n } else if (input != \"\") {\n try {\n tmp = run(input, env);\n std::cout << \" => \" << tmp.debug() << std::endl;\n code += input + \"\\n\";\n } catch (Error &e) {\n std::cerr << e.description() << std::endl;\n } catch (std::runtime_error &e) {\n std::cerr << e.what() << std::endl;\n }\n }\n }\n#endif\n}\n\n// Does this environment, or its parent environment, have a variable?\nbool Environment::has(std::string name) const {\n // Find the value in the map\n std::map<std::string, Value>::const_iterator itr = defs.find(name);\n if (itr != defs.end())\n // If it was found\n return true;\n else if (parent_scope != NULL)\n // If it was not found in the current environment,\n // try to find it in the parent environment\n return parent_scope->has(name);\n else return false;\n}\n\n// Get the value associated with this name in this scope\nValue Environment::get(std::string name) const {\n // Meta operations\n if (name == \"eval\") return Value(\"eval\", builtin::eval);\n if (name == \"type\") return Value(\"type\", builtin::get_type_name);\n if (name == \"parse\") return Value(\"parse\", builtin::parse);\n\n // Special forms\n if (name == \"do\") return Value(\"do\", builtin::do_block);\n if (name == \"if\") return Value(\"if\", builtin::if_then_else);\n if (name == \"for\") return Value(\"for\", builtin::for_loop);\n if (name == \"while\") return Value(\"while\", builtin::while_loop);\n if (name == \"scope\") return Value(\"scope\", builtin::scope);\n if (name == \"quote\") return Value(\"quote\", builtin::quote);\n if (name == \"defun\") return Value(\"defun\", builtin::defun);\n if (name == \"define\") return Value(\"define\", builtin::define);\n if (name == \"lambda\") return Value(\"lambda\", builtin::lambda);\n\n // Comparison operations\n if (name == \"=\") return Value(\"=\", builtin::eq);\n if (name == \"!=\") return Value(\"!=\", builtin::neq);\n if (name == \">\") return Value(\">\", builtin::greater);\n if (name == \"<\") return Value(\"<\", builtin::less);\n if (name == \">=\") return Value(\">=\", builtin::greater_eq);\n if (name == \"<=\") return Value(\"<=\", builtin::less_eq);\n\n // Arithmetic operations\n if (name == \"+\") return Value(\"+\", builtin::sum);\n if (name == \"-\") return Value(\"-\", builtin::subtract);\n if (name == \"*\") return Value(\"*\", builtin::product);\n if (name == \"/\") return Value(\"/\", builtin::divide);\n if (name == \"%\") return Value(\"%\", builtin::remainder);\n\n // List operations\n if (name == \"list\") return Value(\"list\", builtin::list);\n if (name == \"insert\") return Value(\"insert\", builtin::insert);\n if (name == \"index\") return Value(\"index\", builtin::index);\n if (name == \"remove\") return Value(\"remove\", builtin::remove);\n\n if (name == \"len\") return Value(\"len\", builtin::len);\n\n if (name == \"push\") return Value(\"push\", builtin::push);\n if (name == \"pop\") return Value(\"pop\", builtin::pop);\n if (name == \"head\") return Value(\"head\", builtin::head);\n if (name == \"tail\") return Value(\"tail\", builtin::tail);\n if (name == \"first\") return Value(\"first\", builtin::head);\n if (name == \"last\") return Value(\"last\", builtin::pop);\n if (name == \"range\") return Value(\"range\", builtin::range);\n\n // Functional operations\n if (name == \"map\") return Value(\"map\", builtin::map_list);\n if (name == \"filter\") return Value(\"filter\", builtin::filter_list);\n if (name == \"reduce\") return Value(\"reduce\", builtin::reduce_list);\n\n // IO operations\n #ifdef USE_STD\n if (name == \"exit\") return Value(\"exit\", builtin::exit);\n if (name == \"quit\") return Value(\"quit\", builtin::exit);\n if (name == \"print\") return Value(\"print\", builtin::print);\n if (name == \"input\") return Value(\"input\", builtin::input);\n if (name == \"random\") return Value(\"random\", builtin::random);\n if (name == \"include\") return Value(\"include\", builtin::include);\n if (name == \"os-cmd\") return Value(\"os-cmd\", builtin::os_cmd);\n if (name == \"read-file\") return Value(\"read-file\", builtin::read_file);\n if (name == \"write-file\") return Value(\"write-file\", builtin::write_file);\n #endif\n\n // String operations\n if (name == \"debug\") return Value(\"debug\", builtin::debug);\n if (name == \"replace\") return Value(\"replace\", builtin::replace);\n if (name == \"display\") return Value(\"display\", builtin::display);\n \n // Casting operations\n if (name == \"int\") return Value(\"int\", builtin::cast_to_int);\n if (name == \"float\") return Value(\"float\", builtin::cast_to_float);\n\n // Constants\n if (name == \"endl\") return Value::string(\"\\n\");\n \n std::map<std::string, Value>::const_iterator itr = defs.find(name);\n if (itr != defs.end()) return itr->second;\n else if (parent_scope != NULL) {\n itr = parent_scope->defs.find(name);\n if (itr != parent_scope->defs.end()) return itr->second;\n else return parent_scope->get(name);\n }\n\n throw Error(Value::atom(name), *this, ATOM_NOT_DEFINED);\n}\n\nint main(int argc, const char **argv) {\n Environment env;\n std::vector<Value> args;\n for (int i=0; i<argc; i++)\n args.push_back(Value::string(argv[i]));\n env.set(\"cmd-args\", Value(args));\n\n #ifdef USE_STD\n srand(time(NULL));\n #endif\n try {\n run(\"" (add-escapes code) "\", env);\n } catch (Error &e) {\n #ifdef USE_STD\n std::cerr << e.description() << std::endl;\n #endif\n } catch (std::runtime_error &e) {\n #ifdef USE_STD\n std::cerr << e.what() << std::endl;\n #endif\n }\n return 0;\n}"
)
)
(defun second (l) (index l 1))
(define out-file "out.cpp")
(define out-exe "out")
(if (<= (len cmd-args) 1)
(print "Too few arguments")
(write-file out-file (compile 1 1 (read-file (second cmd-args))))
)
(os-cmd (+ "g++ " out-file " -o " out-exe))