Moving files into new locations
This commit is contained in:
139
include/chaiscript/chaiscript.hpp
Normal file
139
include/chaiscript/chaiscript.hpp
Normal file
@@ -0,0 +1,139 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See LICENSE.TXT for details.
|
||||
|
||||
#ifndef CHAISCRIPT_HPP_
|
||||
#define CHAISCRIPT_HPP_
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <fstream>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "dispatchkit.hpp"
|
||||
#include "bootstrap.hpp"
|
||||
#include "bootstrap_stl.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* Types of AST nodes available to the parser and eval
|
||||
*/
|
||||
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||
Expression, Comparison, Additive, Multiplicative, Negate, Not, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation }; };
|
||||
|
||||
/**
|
||||
* Helper lookup to get the name of each node type
|
||||
*/
|
||||
const char *token_type_to_string(int tokentype) {
|
||||
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||
"Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation"};
|
||||
|
||||
return token_types[tokentype];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience type for file positions
|
||||
*/
|
||||
struct File_Position {
|
||||
int line;
|
||||
int column;
|
||||
|
||||
File_Position(int file_line, int file_column)
|
||||
: line(file_line), column(file_column) { }
|
||||
|
||||
File_Position() : line(0), column(0) { }
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<struct Token> TokenPtr;
|
||||
|
||||
/**
|
||||
* The struct that doubles as both a parser token and an AST node
|
||||
*/
|
||||
struct Token {
|
||||
std::string text;
|
||||
int identifier;
|
||||
const char *filename;
|
||||
File_Position start, end;
|
||||
|
||||
std::vector<TokenPtr> children;
|
||||
TokenPtr annotation;
|
||||
|
||||
Token(const std::string &token_text, int id, const char *fname) : text(token_text), identifier(id), filename(fname) { }
|
||||
|
||||
Token(const std::string &token_text, int id, const char *fname, int start_line, int start_col, int end_line, int end_col) :
|
||||
text(token_text), identifier(id), filename(fname) {
|
||||
|
||||
start.line = start_line;
|
||||
start.column = start_col;
|
||||
end.line = end_line;
|
||||
end.column = end_col;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors generated inside the parser
|
||||
*/
|
||||
struct Parse_Error {
|
||||
std::string reason;
|
||||
File_Position position;
|
||||
const char *filename;
|
||||
|
||||
Parse_Error(const std::string &why, const File_Position &where, const char *fname) :
|
||||
reason(why), position(where), filename(fname) { }
|
||||
|
||||
Parse_Error(const std::string &why, const TokenPtr &where) : reason(why) {
|
||||
filename = where->filename;
|
||||
position = where->start;
|
||||
}
|
||||
|
||||
virtual ~Parse_Error() throw() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Errors generated inside the evaluator
|
||||
*/
|
||||
struct Eval_Error : public std::runtime_error {
|
||||
std::string reason;
|
||||
TokenPtr location;
|
||||
|
||||
Eval_Error(const std::string &why, const TokenPtr where)
|
||||
: std::runtime_error("Eval error: \"" + why + "\" in '"
|
||||
+ where->filename + "' line: " + boost::lexical_cast<std::string>(where->start.line+1)),
|
||||
reason(why), location(where) { }
|
||||
|
||||
virtual ~Eval_Error() throw() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Special type for returned values
|
||||
*/
|
||||
struct Return_Value {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
TokenPtr location;
|
||||
|
||||
Return_Value(const dispatchkit::Boxed_Value &return_value, const TokenPtr where) : retval(return_value), location(where) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Special type indicating a call to 'break'
|
||||
*/
|
||||
struct Break_Loop {
|
||||
TokenPtr location;
|
||||
|
||||
Break_Loop(const TokenPtr where) : location(where) { }
|
||||
};
|
||||
}
|
||||
|
||||
#include "chaiscript_eval.hpp"
|
||||
#include "chaiscript_engine.hpp"
|
||||
|
||||
#endif /* CHAISCRIPT_HPP_ */
|
123
include/chaiscript/language/chaiscript_engine.hpp
Normal file
123
include/chaiscript/language/chaiscript_engine.hpp
Normal file
@@ -0,0 +1,123 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See LICENSE.TXT for details.
|
||||
|
||||
#ifndef CHAISCRIPT_ENGINE_HPP_
|
||||
#define CHAISCRIPT_ENGINE_HPP_
|
||||
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
#include "chaiscript_prelude.hpp"
|
||||
#include "chaiscript_parser.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
template <typename Eval_Engine>
|
||||
class ChaiScript_System {
|
||||
Eval_Engine engine;
|
||||
ChaiScript_Parser parser;
|
||||
|
||||
public:
|
||||
ChaiScript_System() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current evaluation engine
|
||||
*/
|
||||
Eval_Engine &get_eval_engine() {
|
||||
return engine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the contents of an AST node, including its children, recursively
|
||||
*/
|
||||
void debug_print(TokenPtr t, std::string prepend = "") {
|
||||
std::cout << prepend << "(" << token_type_to_string(t->identifier) << ") " << t->text << " : " << t->start.line << ", " << t->start.column << std::endl;
|
||||
for (unsigned int j = 0; j < t->children.size(); ++j) {
|
||||
debug_print(t->children[j], prepend + " ");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given boxed string, used during eval() inside of a script
|
||||
*/
|
||||
const dispatchkit::Boxed_Value eval(const std::vector<dispatchkit::Boxed_Value> &vals) {
|
||||
std::string val;
|
||||
val = dispatchkit::boxed_cast<std::string &>(vals[0]);
|
||||
|
||||
return evaluate_string(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for loading a file
|
||||
*/
|
||||
std::string load_file(const char *filename) {
|
||||
std::ifstream infile (filename, std::ios::in | std::ios::ate);
|
||||
|
||||
if (!infile.is_open()) {
|
||||
std::string fname = filename;
|
||||
throw std::runtime_error("Can not open: " + fname);
|
||||
}
|
||||
|
||||
std::streampos size = infile.tellg();
|
||||
infile.seekg(0, std::ios::beg);
|
||||
|
||||
std::vector<char> v(size);
|
||||
infile.read(&v[0], size);
|
||||
|
||||
std::string ret_val (v.empty() ? std::string() : std::string (v.begin(), v.end()).c_str());
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds all the requirements for ChaiScript, including its evaluator and a run of its prelude.
|
||||
*/
|
||||
void build_eval_system() {
|
||||
dispatchkit::Bootstrap::bootstrap(engine);
|
||||
dispatchkit::bootstrap_vector<std::vector<dispatchkit::Boxed_Value> >(engine, "Vector");
|
||||
dispatchkit::bootstrap_string<std::string>(engine, "string");
|
||||
dispatchkit::bootstrap_map<std::map<std::string, dispatchkit::Boxed_Value> >(engine, "Map");
|
||||
dispatchkit::bootstrap_pair<std::pair<dispatchkit::Boxed_Value, dispatchkit::Boxed_Value > >(engine, "Pair");
|
||||
|
||||
engine.register_function(boost::shared_ptr<dispatchkit::Proxy_Function>(
|
||||
new dispatchkit::Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::eval, boost::ref(*this), _1), 1)), "eval");
|
||||
|
||||
evaluate_string(chaiscript_prelude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the given string in by parsing it and running the results through the evaluator
|
||||
*/
|
||||
dispatchkit::Boxed_Value evaluate_string(const std::string &input, const char *filename = "__EVAL__") {
|
||||
//debug_print(tokens);
|
||||
dispatchkit::Boxed_Value value;
|
||||
parser.clear_match_stack();
|
||||
|
||||
try {
|
||||
if (parser.parse(input, filename)) {
|
||||
//parser.show_match_stack();
|
||||
value = eval_token<Eval_Engine>(engine, parser.ast());
|
||||
}
|
||||
}
|
||||
catch (const Return_Value &rv) {
|
||||
value = rv.retval;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file specified by filename, evaluates it, and returns the result
|
||||
*/
|
||||
dispatchkit::Boxed_Value evaluate_file(const char *filename) {
|
||||
return evaluate_string(load_file(filename), filename);
|
||||
}
|
||||
};
|
||||
|
||||
typedef ChaiScript_System<dispatchkit::Dispatch_Engine> ChaiScript_Engine;
|
||||
}
|
||||
#endif /* CHAISCRIPT_ENGINE_HPP_ */
|
||||
|
877
include/chaiscript/language/chaiscript_eval.hpp
Normal file
877
include/chaiscript/language/chaiscript_eval.hpp
Normal file
@@ -0,0 +1,877 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See LICENSE.TXT for details.
|
||||
|
||||
#ifndef CHAISCRIPT_EVAL_HPP_
|
||||
#define CHAISCRIPT_EVAL_HPP_
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
/**
|
||||
* Helper function that will set up the scope around a function call, including handling the named function parameters
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
const dispatchkit::Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector<std::string> ¶m_names, const std::vector<dispatchkit::Boxed_Value> &vals) {
|
||||
ss.new_scope();
|
||||
|
||||
for (unsigned int i = 0; i < param_names.size(); ++i) {
|
||||
ss.add_object(param_names[i], vals[i]);
|
||||
}
|
||||
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
try {
|
||||
retval = eval_token(ss, node);
|
||||
ss.pop_scope();
|
||||
} catch (const Return_Value &rv) {
|
||||
retval = rv.retval;
|
||||
ss.pop_scope();
|
||||
} catch (...) {
|
||||
ss.pop_scope();
|
||||
throw;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the top-level file node
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_file(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
for (i = 0; i < node->children.size(); ++i) {
|
||||
retval = eval_token(ss, node->children[i]);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a variable or function name identifier
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_id(Eval_System &ss, TokenPtr node) {
|
||||
|
||||
if (node->text == "true") {
|
||||
return dispatchkit::Boxed_Value(true);
|
||||
}
|
||||
else if (node->text == "false") {
|
||||
return dispatchkit::Boxed_Value(false);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return ss.get_object(node->text);
|
||||
}
|
||||
catch (std::exception &) {
|
||||
throw Eval_Error("Can not find object: " + node->text, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a floating point number
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_float(Eval_System &, TokenPtr node) {
|
||||
return dispatchkit::Boxed_Value(double(atof(node->text.c_str())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an integer
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_int(Eval_System &, TokenPtr node) {
|
||||
return dispatchkit::Boxed_Value(atoi(node->text.c_str()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a quoted string
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_quoted_string(Eval_System &, TokenPtr node) {
|
||||
return dispatchkit::Boxed_Value(node->text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a char group
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_single_quoted_string(Eval_System &, TokenPtr node) {
|
||||
return dispatchkit::Boxed_Value(node->text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a string of equations in reverse order so that the right-most side has precedence
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_equation(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
retval = eval_token(ss, node->children.back());
|
||||
if (node->children.size() > 1) {
|
||||
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
|
||||
if (node->children[i+1]->text == "=") {
|
||||
dispatchkit::Boxed_Value lhs = eval_token(ss, node->children[i]);
|
||||
try {
|
||||
if (lhs.is_unknown())
|
||||
{
|
||||
retval = dispatch(ss.get_function("clone"), dispatchkit::Param_List_Builder() << retval);
|
||||
}
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << lhs;
|
||||
plb << retval;
|
||||
try {
|
||||
retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &){
|
||||
throw Eval_Error("Mismatched types in equation", node->children[i+1]);
|
||||
}
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &){
|
||||
throw Eval_Error("Can not clone right hand side of equation", node->children[i+1]);
|
||||
}
|
||||
}
|
||||
else if (node->children[i+1]->text == ":=") {
|
||||
dispatchkit::Boxed_Value lhs = eval_token(ss, node->children[i]);
|
||||
if (lhs.is_unknown() || dispatchkit::Bootstrap::type_match(lhs, retval)) {
|
||||
lhs.assign(retval);
|
||||
}
|
||||
else {
|
||||
throw Eval_Error("Mismatched types in equation", node->children[i+1]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << eval_token(ss, node->children[i]);
|
||||
plb << retval;
|
||||
try {
|
||||
retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &){
|
||||
throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a variable declaration
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) {
|
||||
ss.add_object(node->children[0]->text, dispatchkit::Boxed_Value());
|
||||
return ss.get_object(node->children[0]->text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates binary boolean operators. Respects short-circuiting rules.
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_expression(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
if (node->children.size() > 1) {
|
||||
for (i = 1; i < node->children.size(); i += 2) {
|
||||
bool lhs;
|
||||
try {
|
||||
lhs = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("Condition not boolean", node);
|
||||
}
|
||||
if (node->children[i]->text == "&&") {
|
||||
if (lhs) {
|
||||
retval = eval_token(ss, node->children[i+1]);
|
||||
}
|
||||
else {
|
||||
retval = dispatchkit::Boxed_Value(false);
|
||||
}
|
||||
}
|
||||
else if (node->children[i]->text == "||") {
|
||||
if (lhs) {
|
||||
retval = dispatchkit::Boxed_Value(true);
|
||||
}
|
||||
else {
|
||||
retval = eval_token(ss, node->children[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates comparison, additions, and multiplications and their relatives
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_comp_add_mul(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
if (node->children.size() > 1) {
|
||||
for (i = 1; i < node->children.size(); i += 2) {
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << retval;
|
||||
plb << eval_token(ss, node->children[i + 1]);
|
||||
|
||||
try {
|
||||
retval = dispatch(ss.get_function(node->children[i]->text), plb);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &){
|
||||
throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an array lookup
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_array_call(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
for (i = 1; i < node->children.size(); ++i) {
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << retval;
|
||||
plb << eval_token(ss, node->children[i]);
|
||||
try {
|
||||
retval = dispatch(ss.get_function("[]"), plb);
|
||||
}
|
||||
catch(std::out_of_range &) {
|
||||
throw Eval_Error("Out of bounds exception", node);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &){
|
||||
throw Eval_Error("Can not find appropriate array lookup '[]' " + node->children[i]->text, node->children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a unary negation
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_negate(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << retval;
|
||||
plb << dispatchkit::Boxed_Value(-1.0);
|
||||
|
||||
try {
|
||||
return dispatch(ss.get_function("*"), plb);
|
||||
}
|
||||
catch(std::exception &){
|
||||
throw Eval_Error("Can not find appropriate negation", node->children[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a unary boolean not
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_not(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
bool cond;
|
||||
try {
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
cond = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]);
|
||||
}
|
||||
return dispatchkit::Boxed_Value(!cond);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates any unary prefix
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_prefix(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
retval = eval_token(ss, node->children[1]);
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << retval;
|
||||
|
||||
try {
|
||||
return dispatch(ss.get_function(node->children[0]->text), plb);
|
||||
}
|
||||
catch(std::exception &){
|
||||
throw Eval_Error("Can not find appropriate prefix", node->children[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates (and generates) an inline array initialization
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_inline_array(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
try {
|
||||
retval = dispatch(ss.get_function("Vector"), dispatchkit::Param_List_Builder());
|
||||
if (node->children.size() > 0) {
|
||||
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
||||
try {
|
||||
dispatchkit::Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]);
|
||||
dispatch(ss.get_function("push_back"), dispatchkit::Param_List_Builder() << retval << tmp);
|
||||
}
|
||||
catch (const dispatchkit::dispatch_error &) {
|
||||
throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const dispatchkit::dispatch_error &) {
|
||||
throw Eval_Error("Can not find appropriate 'Vector()'", node);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates (and generates) an inline range initialization
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_inline_range(Eval_System &ss, TokenPtr node) {
|
||||
try {
|
||||
return dispatch(ss.get_function("generate_range"), dispatchkit::Param_List_Builder()
|
||||
<< eval_token(ss, node->children[0]->children[0]->children[0])
|
||||
<< eval_token(ss, node->children[0]->children[0]->children[1]));
|
||||
}
|
||||
catch (const dispatchkit::dispatch_error &) {
|
||||
throw Eval_Error("Unable to generate range vector", node);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates (and generates) an inline map initialization
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_inline_map(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
try {
|
||||
retval = dispatch(ss.get_function("Map"), dispatchkit::Param_List_Builder());
|
||||
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
||||
try {
|
||||
dispatchkit::Boxed_Value key = eval_token(ss, node->children[0]->children[i]->children[0]);
|
||||
dispatchkit::Boxed_Value slot = dispatch(ss.get_function("[]"), dispatchkit::Param_List_Builder() << retval << key);
|
||||
dispatch(ss.get_function("="), dispatchkit::Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1]));
|
||||
}
|
||||
catch (const dispatchkit::dispatch_error &) {
|
||||
throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const dispatchkit::dispatch_error &) {
|
||||
throw Eval_Error("Can not find appropriate 'Map()'", node);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call.
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_fun_call(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
||||
dispatchkit::Dispatch_Engine::Stack new_stack;
|
||||
unsigned int i;
|
||||
|
||||
new_stack.push_back(dispatchkit::Dispatch_Engine::Scope());
|
||||
|
||||
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
|
||||
for (i = 0; i < node->children[1]->children.size(); ++i) {
|
||||
plb << eval_token(ss, node->children[1]->children[i]);
|
||||
}
|
||||
}
|
||||
dispatchkit::Boxed_Value fn;
|
||||
try {
|
||||
fn = eval_token(ss, node->children[0]);
|
||||
}
|
||||
catch(Eval_Error &ee) {
|
||||
ss.set_stack(prev_stack);
|
||||
throw Eval_Error(ee.reason, node->children[0]);
|
||||
}
|
||||
try {
|
||||
ss.set_stack(new_stack);
|
||||
retval = (*dispatchkit::boxed_cast<boost::shared_ptr<dispatchkit::Proxy_Function> >(fn))(plb);
|
||||
ss.set_stack(prev_stack);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &e){
|
||||
ss.set_stack(prev_stack);
|
||||
throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]);
|
||||
}
|
||||
catch(Return_Value &rv) {
|
||||
ss.set_stack(prev_stack);
|
||||
retval = rv.retval;
|
||||
}
|
||||
catch(...) {
|
||||
ss.set_stack(prev_stack);
|
||||
throw;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a method/attributes invocation
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_dot_access(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
std::vector<std::pair<std::string, boost::shared_ptr<dispatchkit::Proxy_Function> > > fn;
|
||||
dispatchkit::Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
||||
dispatchkit::Dispatch_Engine::Stack new_stack;
|
||||
unsigned int i, j;
|
||||
|
||||
new_stack.push_back(dispatchkit::Dispatch_Engine::Scope());
|
||||
|
||||
//todo: Please extract a single way of doing function calls between this and eval_fun_call
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
if (node->children.size() > 1) {
|
||||
for (i = 1; i < node->children.size(); ++i) {
|
||||
dispatchkit::Param_List_Builder plb;
|
||||
plb << retval;
|
||||
|
||||
if (node->children[i]->children.size() > 1) {
|
||||
for (j = 0; j < node->children[i]->children[1]->children.size(); ++j) {
|
||||
plb << eval_token(ss, node->children[i]->children[1]->children[j]);
|
||||
}
|
||||
}
|
||||
|
||||
std::string fun_name;
|
||||
if (node->children[i]->identifier == Token_Type::Fun_Call) {
|
||||
fun_name = node->children[i]->children[0]->text;
|
||||
}
|
||||
else {
|
||||
fun_name = node->children[i]->text;
|
||||
}
|
||||
|
||||
try {
|
||||
fn = ss.get_function(fun_name);
|
||||
ss.set_stack(new_stack);
|
||||
retval = dispatch(fn, plb);
|
||||
ss.set_stack(prev_stack);
|
||||
}
|
||||
catch(const dispatchkit::dispatch_error &e){
|
||||
ss.set_stack(prev_stack);
|
||||
throw Eval_Error(std::string(e.what()) + " with function '" + fun_name + "'", node->children[i]);
|
||||
}
|
||||
catch(Return_Value &rv) {
|
||||
ss.set_stack(prev_stack);
|
||||
retval = rv.retval;
|
||||
}
|
||||
catch(...) {
|
||||
ss.set_stack(prev_stack);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates an if/elseif/else block
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_if(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
bool cond;
|
||||
try {
|
||||
cond = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("If condition not boolean", node->children[0]);
|
||||
}
|
||||
if (cond) {
|
||||
retval = eval_token(ss, node->children[1]);
|
||||
}
|
||||
else {
|
||||
if (node->children.size() > 2) {
|
||||
i = 2;
|
||||
while ((!cond) && (i < node->children.size())) {
|
||||
if (node->children[i]->text == "else") {
|
||||
retval = eval_token(ss, node->children[i+1]);
|
||||
cond = true;
|
||||
}
|
||||
else if (node->children[i]->text == "elseif") {
|
||||
retval = eval_token(ss, node->children[i+1]);
|
||||
try {
|
||||
cond = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("Elseif condition not boolean", node->children[i+1]);
|
||||
}
|
||||
if (cond) {
|
||||
retval = eval_token(ss, node->children[i+2]);
|
||||
}
|
||||
}
|
||||
i = i + 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a while block
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_while(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
bool cond;
|
||||
try {
|
||||
cond = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("While condition not boolean", node->children[0]);
|
||||
}
|
||||
while (cond) {
|
||||
try {
|
||||
eval_token(ss, node->children[1]);
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
try {
|
||||
cond = dispatchkit::boxed_cast<bool &>(retval);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("While condition not boolean", node->children[0]);
|
||||
}
|
||||
}
|
||||
catch (Break_Loop &) {
|
||||
cond = false;
|
||||
}
|
||||
}
|
||||
return dispatchkit::Boxed_Value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a for block, including the for's conditions, from left to right
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_for(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
dispatchkit::Boxed_Value condition;
|
||||
bool cond;
|
||||
|
||||
try {
|
||||
if (node->children.size() == 4) {
|
||||
eval_token(ss, node->children[0]);
|
||||
condition = eval_token(ss, node->children[1]);
|
||||
}
|
||||
else if (node->children.size() == 3){
|
||||
condition = eval_token(ss, node->children[0]);
|
||||
}
|
||||
cond = dispatchkit::boxed_cast<bool &>(condition);
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("For condition not boolean", node);
|
||||
}
|
||||
while (cond) {
|
||||
try {
|
||||
if (node->children.size() == 4) {
|
||||
eval_token(ss, node->children[3]);
|
||||
eval_token(ss, node->children[2]);
|
||||
condition = eval_token(ss, node->children[1]);
|
||||
}
|
||||
else if (node->children.size() == 3) {
|
||||
eval_token(ss, node->children[2]);
|
||||
eval_token(ss, node->children[1]);
|
||||
condition = eval_token(ss, node->children[0]);
|
||||
}
|
||||
cond = dispatchkit::boxed_cast<bool &>(condition);
|
||||
|
||||
}
|
||||
catch (const dispatchkit::bad_boxed_cast &) {
|
||||
throw Eval_Error("For condition not boolean", node);
|
||||
}
|
||||
catch (Break_Loop &) {
|
||||
cond = false;
|
||||
}
|
||||
}
|
||||
return dispatchkit::Boxed_Value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a function definition
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_def(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
std::vector<std::string> param_names;
|
||||
std::string annotation = node->annotation?node->annotation->text:"";
|
||||
boost::shared_ptr<dispatchkit::Dynamic_Proxy_Function> guard;
|
||||
size_t numparams = 0;
|
||||
std::string function_name = node->children[0]->text;
|
||||
TokenPtr guardnode;
|
||||
|
||||
if ((node->children.size() > 2) && (node->children[1]->identifier == Token_Type::Arg_List)) {
|
||||
numparams = node->children[1]->children.size();
|
||||
for (i = 0; i < numparams; ++i) {
|
||||
param_names.push_back(node->children[1]->children[i]->text);
|
||||
}
|
||||
|
||||
if (node->children.size() > 3) {
|
||||
guardnode = node->children[2];
|
||||
}
|
||||
}
|
||||
else {
|
||||
//no parameters
|
||||
numparams = 0;
|
||||
|
||||
if (node->children.size() > 2) {
|
||||
guardnode = node->children[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (guardnode) {
|
||||
guard = boost::shared_ptr<dispatchkit::Dynamic_Proxy_Function>
|
||||
(new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||
boost::ref(ss), guardnode,
|
||||
param_names, _1), numparams));
|
||||
}
|
||||
|
||||
ss.register_function(boost::shared_ptr<dispatchkit::Proxy_Function>
|
||||
(new dispatchkit::Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||
boost::ref(ss), node->children.back(),
|
||||
param_names, _1), numparams,
|
||||
annotation, guard)), function_name);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a lambda (anonymous function)
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_lambda(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
std::vector<std::string> param_names;
|
||||
size_t numparams = 0;
|
||||
|
||||
if ((node->children.size() > 0) && (node->children[0]->identifier == Token_Type::Arg_List)) {
|
||||
numparams = node->children[0]->children.size();
|
||||
for (i = 0; i < numparams; ++i) {
|
||||
param_names.push_back(node->children[0]->children[i]->text);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
//no parameters
|
||||
numparams = 0;
|
||||
}
|
||||
|
||||
return dispatchkit::Boxed_Value(boost::shared_ptr<dispatchkit::Proxy_Function>(
|
||||
new dispatchkit::Dynamic_Proxy_Function(
|
||||
boost::bind(&eval_function<Eval_System>, boost::ref(ss), node->children.back(), param_names, _1), numparams)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a scoped block. Handles resetting the scope after the block has completed.
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_block(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
unsigned int i;
|
||||
|
||||
ss.new_scope();
|
||||
for (i = 0; i < node->children.size(); ++i) {
|
||||
try {
|
||||
retval = eval_token(ss, node->children[i]);
|
||||
}
|
||||
catch (const chaiscript::Return_Value &rv) {
|
||||
ss.pop_scope();
|
||||
retval = rv.retval;
|
||||
throw;
|
||||
}
|
||||
catch (...) {
|
||||
ss.pop_scope();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
ss.pop_scope();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a return statement
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_return(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
if (node->children.size() > 0) {
|
||||
retval = eval_token(ss, node->children[0]);
|
||||
}
|
||||
else {
|
||||
retval = dispatchkit::Boxed_Value();
|
||||
}
|
||||
throw Return_Value(retval, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates a break statement
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_break(Eval_System &, TokenPtr node) {
|
||||
throw Break_Loop(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* Top-level evaluation dispatch for all AST node types
|
||||
*/
|
||||
template <typename Eval_System>
|
||||
dispatchkit::Boxed_Value eval_token(Eval_System &ss, TokenPtr node) {
|
||||
dispatchkit::Boxed_Value retval;
|
||||
|
||||
switch (node->identifier) {
|
||||
case (Token_Type::File) :
|
||||
retval = eval_file(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Id) :
|
||||
retval = eval_id(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Float) :
|
||||
retval = eval_float(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Int) :
|
||||
retval = eval_int(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Quoted_String) :
|
||||
retval = eval_quoted_string(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Single_Quoted_String) :
|
||||
retval = eval_single_quoted_string(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Equation) :
|
||||
retval = eval_equation(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Var_Decl) :
|
||||
retval = eval_var_decl(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Expression) :
|
||||
retval = eval_expression(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Comparison) :
|
||||
case (Token_Type::Additive) :
|
||||
case (Token_Type::Multiplicative) :
|
||||
retval = eval_comp_add_mul(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Array_Call) :
|
||||
retval = eval_array_call(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Negate) :
|
||||
retval = eval_negate(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Not) :
|
||||
retval = eval_not(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Prefix) :
|
||||
retval = eval_prefix(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Inline_Array) :
|
||||
retval = eval_inline_array(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Inline_Range) :
|
||||
retval = eval_inline_range(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Inline_Map) :
|
||||
retval = eval_inline_map(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Fun_Call) :
|
||||
retval = eval_fun_call(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Dot_Access) :
|
||||
retval = eval_dot_access(ss, node);
|
||||
break;
|
||||
|
||||
case(Token_Type::If) :
|
||||
retval = eval_if(ss, node);
|
||||
break;
|
||||
|
||||
case(Token_Type::While) :
|
||||
retval = eval_while(ss, node);
|
||||
break;
|
||||
|
||||
case(Token_Type::For) :
|
||||
retval = eval_for(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Def) :
|
||||
retval = eval_def(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Lambda) :
|
||||
retval = eval_lambda(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Block) :
|
||||
retval = eval_block(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Return) :
|
||||
retval = eval_return(ss, node);
|
||||
break;
|
||||
|
||||
case (Token_Type::Break) :
|
||||
retval = eval_break(ss, node);
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
#endif /* CHAISCRIPT_EVAL_HPP_ */
|
1541
include/chaiscript/language/chaiscript_parser.hpp
Normal file
1541
include/chaiscript/language/chaiscript_parser.hpp
Normal file
File diff suppressed because it is too large
Load Diff
263
include/chaiscript/language/chaiscript_prelude.hpp
Normal file
263
include/chaiscript/language/chaiscript_prelude.hpp
Normal file
@@ -0,0 +1,263 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See LICENSE.TXT for details.
|
||||
|
||||
#ifndef CHAISCRIPT_PRELUDE_HPP_
|
||||
#define CHAISCRIPT_PRELUDE_HPP_
|
||||
|
||||
|
||||
//Note, the expression "[x,y]" in "collate" is parsed as two separate expressions
|
||||
//by C++, so CODE_STRING, takes two expressions and adds in the missing comma
|
||||
#define CODE_STRING(x, y) #x ", " #y
|
||||
|
||||
#define chaiscript_prelude CODE_STRING(\
|
||||
# to_string for Pair()\n\
|
||||
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \
|
||||
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \
|
||||
}\
|
||||
# to_string for containers\n\
|
||||
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \
|
||||
"[" + x.join(", ") + "]"; \
|
||||
}\
|
||||
# Basic to_string function\n\
|
||||
def to_string(x) { \
|
||||
return internal_to_string(x); \
|
||||
}\
|
||||
# Prints to console with no carriage return\n\
|
||||
def puts(x) { \
|
||||
print_string(x.to_string()); \
|
||||
} \
|
||||
# Prints to console with carriage return\n\
|
||||
def print(x) { \
|
||||
println_string(x.to_string()); \
|
||||
} \
|
||||
# Returns the maximum value of two numbers\n\
|
||||
def max(a, b) { if (a>b) { a } else { b } } \
|
||||
# Returns the minimum value of two numbers\n\
|
||||
def min(a, b) { if (a<b) { a } else { b } } \
|
||||
# Returns true if the value is odd\n\
|
||||
def odd(x) { if (x % 2 == 1) { true } else { false } } \
|
||||
# Returns true if the value is even\n\
|
||||
def even(x) { if (x % 2 == 0) { true } else { false } } \
|
||||
# Pushes the second value onto the container first value while making a clone of the value\n\
|
||||
def push_back(container, x) { container.push_back_ref(clone(x)) } \n\
|
||||
# Inserts the third value at the position of the second value into the container of the first\n\
|
||||
# while making a clone. \n\
|
||||
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
|
||||
# Performs the second value function over the container first value\n\
|
||||
def for_each(container, func) : call_exists(range, container) { \
|
||||
var range = range(container); \
|
||||
while (!range.empty()) { \
|
||||
func(range.front()); \
|
||||
range.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
def back_inserter(container) { \
|
||||
return bind(push_back, container, _); \
|
||||
}\
|
||||
\
|
||||
def map(container, func, inserter) : call_exists(range, container) { \
|
||||
var range = range(container); \
|
||||
while (!range.empty()) { \
|
||||
inserter(func(range.front())); \
|
||||
range.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Performs the second value function over the container first value. Creates a new Vector with the results\n\
|
||||
def map(container, func) { \
|
||||
var retval = Vector();\
|
||||
map(container, func, back_inserter(retval));\
|
||||
return retval;\
|
||||
}\
|
||||
# Performs the second value function over the container first value. Starts with initial and continues with each element.\n\
|
||||
def foldl(container, func, initial) : call_exists(range, container){ \
|
||||
var retval = initial; \
|
||||
var range = range(container); \
|
||||
while (!range.empty()) { \
|
||||
retval = (func(range.front(), retval)); \
|
||||
range.pop_front(); \
|
||||
} \
|
||||
retval; \
|
||||
} \
|
||||
# Returns the sum of the elements of the given value\n\
|
||||
def sum(container) { foldl(container, `+`, 0.0) } \
|
||||
# Returns the product of the elements of the given value\n\
|
||||
def product(container) { foldl(container, `*`, 1.0) } \
|
||||
# Returns a new Vector with the elements of the first value concatenated with the elements of the second value\n\
|
||||
def concat(x, y) : call_exists(clone, x) { \
|
||||
var retval = x; \
|
||||
var len = y.size(); \
|
||||
var i = 0; \
|
||||
while (i < len) { \
|
||||
retval.push_back(y[i]); \
|
||||
++i; \
|
||||
} \
|
||||
retval; \
|
||||
} \
|
||||
def take(container, num, inserter) : call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
var i = num; \
|
||||
while ((i > 0) && (!r.empty())) { \
|
||||
inserter(r.front()); \
|
||||
r.pop_front(); \
|
||||
--i; \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector with the given number of elements taken from the container\n\
|
||||
def take(container, num) {\
|
||||
var retval = Vector(); \
|
||||
take(container, num, back_inserter(retval)); \
|
||||
return retval; \
|
||||
}\
|
||||
def take_while(container, f, inserter) : call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
while ((!r.empty()) && f(r.front())) { \
|
||||
inserter(r.front()); \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector with the given elements match the second value function\n\
|
||||
def take_while(container, f) {\
|
||||
var retval = Vector(); \
|
||||
take_while(container, f, back_inserter(retval)); \
|
||||
return retval;\
|
||||
}\
|
||||
def drop(container, num, inserter) : call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
var i = num; \
|
||||
while ((i > 0) && (!r.empty())) { \
|
||||
r.pop_front(); \
|
||||
--i; \
|
||||
} \
|
||||
while (!r.empty()) { \
|
||||
inserter(r.front()); \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector with the given number of elements dropped from the given container \n\
|
||||
def drop(container, num) {\
|
||||
var retval = Vector(); \
|
||||
drop(container, num, back_inserter(retval)); \
|
||||
return retval; \
|
||||
}\
|
||||
def drop_while(container, f, inserter) : call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
while ((!r.empty())&& f(r.front())) { \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
while (!r.empty()) { \
|
||||
inserter(r.front()); \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector with the given elements dropped that match the second value function\n\
|
||||
def drop_while(container, f) {\
|
||||
var retval = Vector(); \
|
||||
drop_while(container, f, back_inserter(retval)); \
|
||||
return retval; \
|
||||
}\
|
||||
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\n\
|
||||
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
var retval = r.front(); \
|
||||
r.pop_front(); \
|
||||
retval = func(retval, r.front()); \
|
||||
r.pop_front(); \
|
||||
while (!r.empty()) { \
|
||||
retval = func(retval, r.front()); \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
retval; \
|
||||
} \
|
||||
# Returns a string of the elements in container delimited by the second value string\n\
|
||||
def join(container, delim) { \
|
||||
var retval = ""; \
|
||||
var range = range(container); \
|
||||
if (!range.empty()) { \
|
||||
retval += to_string(range.front()); \
|
||||
range.pop_front(); \
|
||||
while (!range.empty()) { \
|
||||
retval += delim; \
|
||||
retval += to_string(range.front()); \
|
||||
range.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
retval; \
|
||||
} \
|
||||
def filter(container, f, inserter) : call_exists(range, container) { \
|
||||
var r = range(container); \
|
||||
while (!r.empty()) { \
|
||||
if (f(r.front())) { \
|
||||
inserter(r.front()); \
|
||||
} \
|
||||
r.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector which match the second value function\n\
|
||||
def filter(container, f) { \
|
||||
var retval = Vector(); \
|
||||
filter(container, f, back_inserter(retval));\
|
||||
return retval;\
|
||||
}\
|
||||
def generate_range(x, y, inserter) { \
|
||||
var i = x; \
|
||||
while (i <= y) { \
|
||||
inserter(i); \
|
||||
++i; \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector which represents the range from the first value to the second value\n\
|
||||
def generate_range(x, y) { \
|
||||
var retval = Vector(); \
|
||||
generate_range(x,y,back_inserter(retval)); \
|
||||
return retval; \
|
||||
}\
|
||||
# Returns a new Vector with the first value to the second value as its elements\n\
|
||||
def collate(x, y) { \
|
||||
[x, y]; \
|
||||
} \
|
||||
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \
|
||||
var r_x = range(x); \
|
||||
var r_y = range(y); \
|
||||
while (!r_x.empty() && !r_y.empty()) { \
|
||||
inserter(f(r_x.front(), r_y.front())); \
|
||||
r_x.pop_front(); \
|
||||
r_y.pop_front(); \
|
||||
} \
|
||||
} \
|
||||
# Returns a new Vector which joins matching elements of the second and third value with the first value function\n\
|
||||
def zip_with(f, x, y) { \
|
||||
var retval = Vector(); \
|
||||
zip_with(f,x,y,back_inserter(retval)); \
|
||||
return retval;\
|
||||
}\
|
||||
# Returns a new Vector which joins matching elements of the first and second\n\
|
||||
def zip(x, y) { \
|
||||
zip_with(collate, x, y); \
|
||||
}\
|
||||
# Returns the position of the second value string in the first value string\n\
|
||||
def find(str, substr) { \
|
||||
return int(find(str, substr, size_t(0))); \
|
||||
} \
|
||||
# Returns the position of last match of the second value string in the first value string\n\
|
||||
def rfind(str, substr) { \
|
||||
return int(rfind(str, substr, size_t(-1))); \
|
||||
} \
|
||||
# Returns the position of the first match of elements in the second value string in the first value string\n\
|
||||
def find_first_of(str, list) { \
|
||||
return int(find_first_of(str, list, size_t(0))); \
|
||||
} \
|
||||
# Returns the position of the last match of elements in the second value string in the first value string\n\
|
||||
def find_last_of(str, list) { \
|
||||
return int(find_last_of(str, list, size_t(-1))); \
|
||||
} \
|
||||
# Returns the position of the first non-matching element in the second value string in the first value string\n\
|
||||
def find_first_not_of(str, list) { \
|
||||
return int(find_first_not_of(str, list, size_t(0))); \
|
||||
} \
|
||||
# Returns the position of the last non-matching element in the second value string in the first value string\n\
|
||||
def find_last_not_of(str, list) { \
|
||||
return int(find_last_not_of(str, list, size_t(-1))); \
|
||||
} \
|
||||
)
|
||||
|
||||
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
Reference in New Issue
Block a user