00001
00002
00003
00004
00005
00006
00007
00013
00014 #ifndef EVAL_EVAL_H
00015 #define EVAL_EVAL_H
00016
00017 #include <iostream>
00018 #include <stdexcept>
00019 #include <fstream>
00020 #include <string>
00021 #include <utility>
00022
00023 #define PHOENIX_LIMIT 4
00024
00025 #include <boost/spirit/core.hpp>
00026 #include <boost/spirit/attribute.hpp>
00027 #include <boost/spirit/utility/distinct.hpp>
00028 #include <boost/spirit/utility/confix.hpp>
00029 #include <boost/spirit/utility/escape_char.hpp>
00030 #include <boost/spirit/phoenix/functions.hpp>
00031 #include <boost/scoped_array.hpp>
00032
00033 #include "execution_context.hpp"
00034
00035
00036
00037
00038 namespace eval
00039 {
00040 namespace detail
00041 {
00042
00043 struct eval_closure_str : boost::spirit::closure<eval_closure_str, std::string>
00044 {
00045 member1 str;
00046 };
00047
00048 struct eval_closure_str_char : boost::spirit::closure<eval_closure_str_char,
00049 std::string, char>
00050 {
00051 member1 str;
00052 member2 temp;
00053 };
00054
00055 struct eval_closure_str2 : boost::spirit::closure<eval_closure_str2, std::string,
00056 std::string>
00057 {
00058 member1 str;
00059 member2 temp;
00060 };
00061
00062 struct eval_closure_val : boost::spirit::closure<eval_closure_val, val>
00063 {
00064 member1 value;
00065 };
00066
00067 struct eval_closure_exp : boost::spirit::closure<eval_closure_exp, val, std::string>
00068 {
00069 member1 value;
00070 member2 op;
00071 };
00072
00073 struct eval_closure_args : boost::spirit::closure<eval_closure_args,
00074 val, std::string, fwrap_args>
00075 {
00076 member1 rv;
00077 member2 name;
00078 member3 args;
00079 };
00080
00081
00082 struct push_back_
00083 {
00084 template<typename ContainerT, typename ItemT>
00085 struct result
00086 {
00087 typedef void type;
00088 };
00089
00090 template <typename ContainerT, typename ItemT>
00091 void operator()(ContainerT& c, const ItemT& item) const
00092 {
00093 c.push_back(item);
00094 }
00095 };
00096
00097 phoenix::function<push_back_> const push_back = push_back_();
00098
00099
00100
00101 struct declare_global_
00102 {
00103 template<typename ExecutionContextT, typename NameT>
00104 struct result
00105 {
00106 typedef void type;
00107 };
00108
00109 template<typename ExecutionContextT, typename NameT>
00110 void operator()(ExecutionContextT *e, NameT& name) const
00111 {
00112 e->add_global(name, val());
00113 }
00114 };
00115
00116 const phoenix::function<declare_global_> declare_global = declare_global_();
00117
00118
00119
00120 struct lookup_global_
00121 {
00122 template<typename ExecutionContextT, typename NameT>
00123 struct result
00124 {
00125 typedef val& type;
00126 };
00127
00128 template<typename ExecutionContextT, typename NameT>
00129 val& operator()(ExecutionContextT *e, NameT& name) const
00130 {
00131 return e->get_global(name);
00132 }
00133 };
00134
00135 const phoenix::function<lookup_global_> lookup_global = lookup_global_();
00136
00137
00138
00139 struct call_function_
00140 {
00141 template<typename ExecutionContextT, typename NameT, typename ArgsVecT>
00142 struct result
00143 {
00144 typedef val type;
00145 };
00146
00147 template<typename ExecutionContextT, typename NameT, typename ArgsVecT>
00148 val operator()(ExecutionContextT *e, NameT& name, ArgsVecT& args) const
00149 {
00150 return e->call_function(name, args);
00151 }
00152 };
00153
00154 const phoenix::function<call_function_> call_function = call_function_();
00155
00156
00157
00158 struct call_method_
00159 {
00160 template<typename ExecutionContextT, typename NameT, typename ArgsVecT>
00161 struct result
00162 {
00163 typedef val type;
00164 };
00165
00166 template<typename ExecutionContextT, typename NameT, typename ArgsVecT>
00167 val operator()(ExecutionContextT *e, NameT& name, ArgsVecT& args) const
00168 {
00169 return e->call_method(name, args);
00170 }
00171 };
00172
00173 const phoenix::function<call_method_> call_method = call_method_();
00174
00175
00176 struct call_operator_
00177 {
00178 template<typename ExecutionContextT, typename NameT, typename LhsT, typename RhsT>
00179 struct result
00180 {
00181 typedef val type;
00182 };
00183
00184 template<typename ExecutionContextT, typename NameT, typename LhsT, typename RhsT>
00185 val operator()(ExecutionContextT *e, NameT& op, LhsT& lhs, RhsT& rhs) const
00186 {
00187 fwrap_args args;
00188 args.push_back(lhs);
00189 args.push_back(rhs);
00190 return e->call_function_or_method("operator" + op, args);
00191 }
00192 };
00193
00194 const phoenix::function<call_operator_> call_operator = call_operator_();
00195
00196
00197
00198 struct wrap_literal_
00199 {
00200 template<typename ValT>
00201 struct result
00202 {
00203 typedef val type;
00204 };
00205
00206 template<typename ValT>
00207 val operator()(ValT v) const
00208 {
00209 const ValT *val_ptr = new ValT(v);
00210 return val(val_ptr, TRANSFER_OWNERSHIP);
00211 }
00212 };
00213
00214 const phoenix::function<wrap_literal_> wrap_literal = wrap_literal_();
00215
00216
00217
00218 struct wrap_string_literal_
00219 {
00220 template<typename StringT>
00221 struct result
00222 {
00223 typedef val type;
00224 };
00225
00226 template<typename StringT>
00227 val operator()(StringT& str) const
00228 {
00229 char *c_str = new char [str.size() + 1];
00230 std::memcpy(c_str, str.c_str(), str.size());
00231 c_str[str.size()] = '\0';
00232 return val(const_cast<const char *>(c_str), TRANSFER_OWNERSHIP_ARRAY);
00233 }
00234 };
00235
00236 const phoenix::function<wrap_string_literal_> wrap_string_literal = wrap_string_literal_();
00237
00238
00239
00240 const boost::spirit::distinct_parser<> keyword_p("a-zA-Z0-9_");
00241
00242
00243 struct eval_p : public boost::spirit::grammar<eval_p>
00244 {
00245 explicit eval_p(execution_context& e)
00246 : _e(&e)
00247 {
00248 }
00249
00250 template<typename ScannerT>
00251 struct definition
00252 {
00253 definition(const eval_p& self)
00254 {
00255
00256 prog = *stmt;
00257
00258 stmt = ( declaration
00259 | assignment
00260 | expression
00261 )
00262 >> boost::spirit::ch_p(';');
00263
00264
00265
00266
00267
00268 identifier = +(
00269 !boost::spirit::str_p("::")[identifier.str += "::"]
00270 >>
00271 boost::spirit::lexeme_d[
00272 (
00273 boost::spirit::alpha_p
00274 | boost::spirit::ch_p('_')
00275 )
00276 >>
00277 *(
00278 boost::spirit::alnum_p
00279 | boost::spirit::ch_p('_')
00280 )
00281 ]
00282 [
00283 identifier.str +=
00284 phoenix::construct_<std::string>
00285 (phoenix::arg1, phoenix::arg2)
00286 ]
00287 >>
00288 !(
00289 boost::spirit::ch_p('<')[identifier.temp = "<"]
00290 >>
00291 (
00292 boost::spirit::ch_p('>')[identifier.temp += ">"]
00293 |
00294 (
00295 identifier[identifier.temp += phoenix::arg1]
00296 >>
00297 *(
00298 boost::spirit::ch_p(',')[identifier.temp += ',']
00299 >> identifier[identifier.temp += phoenix::arg1]
00300 )
00301 >> boost::spirit::ch_p('>')[identifier.temp += '>']
00302 )
00303 )
00304 )[identifier.str += identifier.temp]
00305 )
00306 ;
00307
00308
00309 declaration = keyword_p("val")
00310 >> identifier
00311 [declare_global(phoenix::val(self._e), phoenix::arg1)]
00312 ;
00313
00314 assignment = identifier[assignment.str = phoenix::arg1]
00315 >>
00316 boost::spirit::ch_p('=')
00317 >>
00318 expression[lookup_global(phoenix::val(self._e), assignment.str)
00319 = phoenix::arg1]
00320 ;
00321
00322
00323 expression = unary_expression[expression.value = phoenix::arg1]
00324 >> *( op[expression.op = phoenix::arg1]
00325 >> unary_expression
00326 [expression.value = call_operator(phoenix::val(self._e),
00327 expression.op,
00328 expression.value,
00329 phoenix::arg1)]
00330 )
00331 ;
00332
00333
00334
00335 op = ( boost::spirit::str_p("<<")
00336 | boost::spirit::str_p(">>")
00337 )[op.str = phoenix::construct_<std::string>(phoenix::arg1, phoenix::arg2)]
00338 ;
00339
00340 unary_expression = method_call[unary_expression.value = phoenix::arg1]
00341 | fn_call[unary_expression.value = phoenix::arg1]
00342 | terminal[unary_expression.value = phoenix::arg1]
00343 ;
00344
00345 terminal = identifier[terminal.value = lookup_global(phoenix::val(self._e),
00346 phoenix::arg1)]
00347 | boost::spirit::strict_real_p[terminal.value =
00348 wrap_literal(phoenix::arg1)]
00349 | boost::spirit::int_p[terminal.value = wrap_literal(phoenix::arg1)]
00350 | string_literal[terminal.value = wrap_string_literal(phoenix::arg1)]
00351
00352
00353
00354
00355
00356 ;
00357
00358 string_literal = boost::spirit::lexeme_d[
00359 boost::spirit::ch_p('"')
00360 >> *( boost::spirit::c_escape_ch_p
00361 [string_literal.temp = phoenix::arg1]
00362 - boost::spirit::ch_p('"')
00363 ) [string_literal.str += string_literal.temp]
00364 >> boost::spirit::ch_p('"')
00365 ]
00366 ;
00367
00368 fn_call = identifier[fn_call.name = phoenix::arg1]
00369 >> boost::spirit::ch_p('(')
00370 >> ( boost::spirit::ch_p(')')
00371 | ( expression[push_back(fn_call.args, phoenix::arg1)]
00372 >> *( boost::spirit::ch_p(',')
00373 >> expression[push_back(fn_call.args,
00374 phoenix::arg1)]
00375 )
00376 >> boost::spirit::ch_p(')')
00377 )
00378 )
00379 [fn_call.rv = call_function(phoenix::val(self._e),
00380 fn_call.name, fn_call.args)]
00381 ;
00382
00383 method_call = identifier[method_call.name = phoenix::arg1]
00384 >> boost::spirit::ch_p('.')
00385 [push_back(method_call.args, lookup_global(
00386 phoenix::val(self._e),
00387 method_call.name))]
00388 >> identifier[method_call.name = phoenix::arg1]
00389 >> boost::spirit::ch_p('(')
00390 >> ( boost::spirit::ch_p(')')
00391 | ( expression[push_back(method_call.args, phoenix::arg1)]
00392 >> *( boost::spirit::ch_p(',')
00393 >> expression[push_back(method_call.args,
00394 phoenix::arg1)]
00395 )
00396 >> boost::spirit::ch_p(')')
00397 )
00398 )
00399 [method_call.rv = call_method(phoenix::val(self._e),
00400 method_call.name, method_call.args)]
00401 ;
00402
00403 }
00404
00405
00406 typedef boost::spirit::rule<ScannerT, eval_closure_str::context_t> str_rule_t;
00407 typedef boost::spirit::rule<ScannerT, eval_closure_str2::context_t> str2_rule_t;
00408 typedef boost::spirit::rule<ScannerT, eval_closure_str_char::context_t>
00409 str_char_rule_t;
00410 typedef boost::spirit::rule<ScannerT, eval_closure_val::context_t> val_rule_t;
00411 typedef boost::spirit::rule<ScannerT, eval_closure_exp::context_t> exp_rule_t;
00412 typedef boost::spirit::rule<ScannerT, eval_closure_args::context_t> args_rule_t;
00413 str_rule_t assignment, op;
00414 str2_rule_t identifier;
00415 str_char_rule_t string_literal;
00416 val_rule_t binary_expression, unary_expression, terminal;
00417 exp_rule_t expression;
00418 args_rule_t fn_call, method_call;
00419
00420 boost::spirit::rule<ScannerT> declaration, stmt, prog;
00421
00422 const boost::spirit::rule<ScannerT>& start() const
00423 {
00424 return prog;
00425 }
00426 };
00427
00428 execution_context *_e;
00429 };
00430
00431 struct space_comment_p : public boost::spirit::grammar<space_comment_p>
00432 {
00433 template<typename ScannerT>
00434 struct definition
00435 {
00436 definition(const space_comment_p& self)
00437 {
00438 space_or_comment = boost::spirit::space_p
00439 | boost::spirit::comment_p("/*", "*/")
00440 | boost::spirit::comment_p("//")
00441 ;
00442 }
00443
00444 boost::spirit::rule<ScannerT> space_or_comment;
00445
00446 const boost::spirit::rule<ScannerT>& start() const
00447 {
00448 return space_or_comment;
00449 }
00450 };
00451 };
00452
00453
00454 }
00455
00456
00457 class file_not_found_exception : public std::invalid_argument
00458 {
00459 public:
00460 explicit file_not_found_exception(const std::string& file)
00461 : std::invalid_argument("eval::file_not_found_exception: Failed to read " + file)
00462 {
00463 }
00464 };
00465
00466 class syntax_error : public std::logic_error
00467 {
00468 public:
00469 explicit syntax_error(const std::string& err, const char *code)
00470 : std::logic_error("eval::syntax_error: '" + err + "' at '"
00471 + (std::strlen(code) > 100 ? std::string(code, 100)
00472 : std::string(code))
00473 + "'")
00474 {
00475 }
00476 };
00477
00478
00495 inline void eval(execution_context& e, const char *code)
00496 {
00497 detail::eval_p p(e);
00498 detail::space_comment_p skip_p;
00499 boost::spirit::parse_info<> info = boost::spirit::parse(code, p, skip_p);
00500
00501
00502
00503
00504 if (!info.full && (!info.hit || !boost::spirit::parse(info.stop, *skip_p).full))
00505 {
00506 throw syntax_error("failed parsing somewhere around", info.stop);
00507 }
00508 }
00509
00514 inline void eval_file(execution_context& e, const char *filename)
00515 {
00516
00517
00518 std::ifstream file(filename, std::ios::in | std::ios::binary | std::ios::ate);
00519 if(!file.is_open())
00520 {
00521 throw file_not_found_exception(filename);
00522 }
00523 std::ifstream::pos_type file_size = file.tellg();
00524 boost::scoped_array<char> data(new char [static_cast<std::size_t>(file_size) + 1]);
00525 file.seekg(0, std::ios::beg);
00526 file.read(data.get(), file_size);
00527 if(!file)
00528 {
00529 throw file_not_found_exception(filename);
00530 }
00531 file.close();
00532 data[file_size] = '\0';
00533 eval(e, data.get());
00534 }
00535
00541
00542
00543
00544
00545 }
00546
00547
00548 #endif