Add Lazy, a lazy-evaluating version of Groovy
[Funky.git] / lib / Funky / Private / Evaluator.h
blob57a37bac78d7145480d7c974ffbee42bea4e386f
1 /* Funky: a light-weight embeddable programming language
2 * Copyright (c) 2007, Ronald Landheer-Cieslak
3 * All rights reserved
4 *
5 * This is free software. You may distribute it and/or modify it and
6 * distribute modified forms provided that the following terms are met:
8 * * Redistributions of the source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the distribution;
13 * * None of the names of the authors of this software may be used to endorse
14 * or promote this software, derived software or any distribution of this
15 * software or any distribution of which this software is part, without
16 * prior written permission from the authors involved;
17 * * Unless you have received a written statement from Ronald Landheer-Cieslak
18 * that says otherwise, the terms of the GNU General Public License, as
19 * published by the Free Software Foundation, version 2 or (at your option)
20 * any later version, also apply.
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
34 #ifndef _funky_private_evaluator_h
35 #define _funky_private_evaluator_h
37 #include "StoredFunctions.h"
38 #include "../Details/Fetcher.h"
40 namespace Funky
42 namespace Private
44 template < typename T >
45 struct get_lexical_cast_target_type
47 typedef T type;
50 template < typename T >
51 struct get_lexical_cast_target_type< Details::Fetcher< T > >
53 typedef T type;
56 template < typename Arguments >
57 struct Evaluator
59 typedef boost::spirit::tree_match< const char * >::tree_iterator TreeIterator; // This is the type of an iterator with which we can traverse the parse tree
60 typedef boost::spirit::tree_node< boost::spirit::node_val_data<> > Node; // This is the type of a node in the parse tree
61 typedef std::stack< std::pair< Node, Arguments * > > Stack;
63 Evaluator(const StoredFunctions< Arguments > & functions)
64 : functions_(functions),
65 value_(0)
66 { /* no-op */ }
68 Evaluator(const StoredFunctions< Arguments > & functions, const boost::any & user)
69 : functions_(functions),
70 value_(0),
71 user_(user)
72 { /* no-op */ }
74 Evaluator & operator()(const Node & node, Arguments * arguments)
76 stack_.push(std::make_pair(node, arguments));
77 Loki::ScopeGuard stack_guard(Loki::MakeObjGuard(stack_, &Stack::pop));
79 Arguments args; // these are the ones we will pass to the next function we call
81 if (stack_.top().first.value.id() == function_name_id__)
83 std::string function_to_call(stack_.top().first.value.begin(), stack_.top().first.value.end());
84 // look up the function
85 typename StoredFunctions< Arguments >::const_iterator which(functions_.find(function_to_call));
86 if (which == functions_.end() && function_to_call != "shift")
87 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__);
88 else if (function_to_call == "shift")
90 if (stack_.top().second->empty())
91 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::no_more_arguments__);
92 else
94 value_ = Arguments(1, stack_.top().second->at(0));
95 stack_.top().second->erase(stack_.top().second->begin());
98 else
100 Arguments no_args;
101 value_ = which->second->call(*this, &no_args);
104 else
105 { // function call with arguments
106 TreeIterator curr(stack_.top().first.children.begin());
108 /* normally, the first node we find is always the name of a
109 * function to call. After that, we will find any number of
110 * arguments to pass to it, but those arguments can be either
111 * literals, parameters passed to us, or statements. If they
112 * are statements, we will need to evaluate them. If they are
113 * literals, we have the value we want; if they are parameters,
114 * they are in the stack's current top. */
115 // get the name of the next function to call
116 assert(curr->value.id() == function_name_id__);
117 std::string function_name(curr->value.begin(), curr->value.end());
118 typename StoredFunctions< Arguments >::const_iterator which(functions_.find(function_name));
119 enum { custom__, if__, defined__ } function_type(custom__);
120 if (which == functions_.end())
122 /* three possibilities: either it's an "if", for which we
123 * have a built-in version right here; or it's a "defined",
124 * in which case there should be one argument, which should be
125 * a parameter, or it's an unknown function, in which case we
126 * throw an exception.
127 * Note that we only start checking whether it's an "if" or
128 * a "defined" *after" we haven't found the function in the
129 * function map: we leave the possibility to the user to
130 * override both built-in operators, just like we leave
131 * him the possibility to override any built-in function.
132 * There is no such thing as a reserved word in Funky. */
133 if (function_name == "if")
134 function_type = if__;
135 else if (function_name == "defined")
136 function_type = defined__;
137 else
138 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__);
140 else
141 { /* we know this function - now call it */ }
142 ++curr;
143 assert(curr->value.id() == comma_separated_list_id__);
144 TreeIterator end(curr->children.end());
145 TreeIterator curr_arg(curr->children.begin());
146 unsigned int argument_index(0);
147 bool evaluate_second(true);
148 bool evaluate_third(true);
149 if (function_type == if__ && std::distance(curr_arg, end) != 6 /* counting commas */)
150 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_count_mismatch__, 3, std::distance(curr_arg, end) / 2);
151 else
152 { /* all is well so far */ }
153 if (function_type == defined__ && std::distance(curr_arg, end) != 2 /* counting commas */)
154 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_count_mismatch__, 1, std::distance(curr_arg, end) / 2);
155 else
156 { /* all is well so far */ }
159 assert(curr_arg == end || *(curr_arg->value.begin()) == ',');
160 if (curr_arg != end)
162 ++curr_arg;
163 assert(curr_arg != end);
164 if ((argument_index == 1 && !evaluate_second) ||
165 (argument_index == 2 && !evaluate_third))
166 { /* skip this argument */ }
167 else
169 switch (curr_arg->value.id().to_long())
171 case literal_id__ :
172 if (function_type == defined__)
173 args.push_back(1); // literals are always defined
174 else
175 args.push_back(boost::lexical_cast< typename get_lexical_cast_target_type< typename Arguments::value_type>::type >(std::string(curr_arg->value.begin(), curr_arg->value.end())));
176 break;
177 case parameter_id__ :
179 std::string parameter_id(std::string(curr_arg->value.begin(), curr_arg->value.end()));
180 assert(parameter_id.size() > 1);
181 if (parameter_id != "@@")
183 unsigned int index(boost::lexical_cast<unsigned int>(parameter_id.substr(1)));
184 if (stack_.top().second->size() <= index && function_type != defined__)
185 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_out_of_range__, stack_.top().second->size() - 1, index);
186 else if (function_type == defined__ && stack_.top().second->size() <= index)
187 args.push_back(0);
188 else if (function_type == defined__)
189 args.push_back(1);
190 else
191 args.push_back(stack_.top().second->at(index));
193 else
195 if (function_type == defined__)
196 args.push_back(!stack_.top().second->empty());
197 else // copy all arguments
198 std::copy(stack_.top().second->begin(), stack_.top().second->end(), std::back_inserter(args));
201 break;
202 case statement_id__ :
204 // can't pass a statement to defined
205 if (function_type == defined__)
206 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unexpected_statement__);
207 else
208 { /* not a defined call */ }
209 Arguments temp_args((*this)(*curr_arg, stack_.top().second).value_);
210 std::copy(temp_args.begin(), temp_args.end(), std::back_inserter(args));
212 break;
213 case function_name_id__ : // a function call without arguments
214 // can't pass a function call to defined
215 if (function_type == defined__)
216 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unexpected_statement__);
217 else
218 { /* not a defined call */ }
220 std::string function_to_call(curr_arg->value.begin(), curr_arg->value.end());
221 // look up the function
222 typename StoredFunctions< Arguments >::const_iterator which(functions_.find(function_to_call));
223 if (which == functions_.end() && function_to_call != "shift")
224 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__);
225 else if (function_to_call == "shift")
227 if (stack_.top().second->empty())
228 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::no_more_arguments__);
229 else
231 args.push_back(stack_.top().second->at(0));
232 stack_.top().second->erase(stack_.top().second->begin());
235 else
237 Arguments no_args;
238 Arguments returned_args(which->second->call(*this, &no_args));
239 std::copy(returned_args.begin(), returned_args.end(), std::back_inserter(args));
242 break;
243 default :
244 throw std::logic_error("Unexpected node type");
247 ++curr_arg;
248 ++argument_index;
249 if (function_type == if__ && argument_index == 1)
251 // this is where we make the choice whether or not to evaluate the next, second argument
252 if (!args.back())
253 evaluate_second = false;
254 else
255 evaluate_third = false;
258 else
259 { /* at the end */ }
260 } while (curr_arg != end);
261 if (function_type != if__ && function_type != defined__)
262 value_ = which->second->call(*this, &args);
263 else
264 value_ = Arguments(1, args.back());
266 return *this;
269 const StoredFunctions< Arguments > & functions_;
270 Stack stack_;
271 Arguments value_;
272 boost::any user_;
277 #endif