1 /* Funky: a light-weight embeddable programming language
2 * Copyright (c) 2007, Ronald Landheer-Cieslak
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"
43 template < typename Arguments
>
46 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
47 typedef boost::spirit::tree_node
< boost::spirit::node_val_data
<> > Node
; // This is the type of a node in the parse tree
48 typedef std::stack
< std::pair
< Node
, Arguments
* > > Stack
;
50 Evaluator(const StoredFunctions
< Arguments
> & functions
)
51 : functions_(functions
),
55 Evaluator(const StoredFunctions
< Arguments
> & functions
, const boost::any
& user
)
56 : functions_(functions
),
61 Evaluator
& operator()(const Node
& node
, Arguments
* arguments
)
63 stack_
.push(std::make_pair(node
, arguments
));
64 Loki::ScopeGuard
stack_guard(Loki::MakeObjGuard(stack_
, &Stack::pop
));
66 Arguments args
; // these are the ones we will pass to the next function we call
68 if (stack_
.top().first
.value
.id() == function_name_id__
)
70 std::string
function_to_call(stack_
.top().first
.value
.begin(), stack_
.top().first
.value
.end());
71 // look up the function
72 typename StoredFunctions
< Arguments
>::const_iterator
which(functions_
.find(function_to_call
));
73 if (which
== functions_
.end() && function_to_call
!= "shift")
74 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__
);
75 else if (function_to_call
== "shift")
77 if (stack_
.top().second
->empty())
78 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::no_more_arguments__
);
81 value_
= Arguments(1, stack_
.top().second
->at(0));
82 stack_
.top().second
->erase(stack_
.top().second
->begin());
88 value_
= which
->second
->call(*this, &no_args
);
92 { // function call with arguments
93 TreeIterator
curr(stack_
.top().first
.children
.begin());
95 /* normally, the first node we find is always the name of a
96 * function to call. After that, we will find any number of
97 * arguments to pass to it, but those arguments can be either
98 * literals, parameters passed to us, or statements. If they
99 * are statements, we will need to evaluate them. If they are
100 * literals, we have the value we want; if they are parameters,
101 * they are in the stack's current top. */
102 // get the name of the next function to call
103 assert(curr
->value
.id() == function_name_id__
);
104 std::string
function_name(curr
->value
.begin(), curr
->value
.end());
105 typename StoredFunctions
< Arguments
>::const_iterator
which(functions_
.find(function_name
));
106 enum { custom__
, if__
, defined__
} function_type(custom__
);
107 if (which
== functions_
.end())
109 /* three possibilities: either it's an "if", for which we
110 * have a built-in version right here; or it's a "defined",
111 * in which case there should be one argument, which should be
112 * a parameter, or it's an unknown function, in which case we
113 * throw an exception.
114 * Note that we only start checking whether it's an "if" or
115 * a "defined" *after" we haven't found the function in the
116 * function map: we leave the possibility to the user to
117 * override both built-in operators, just like we leave
118 * him the possibility to override any built-in function.
119 * There is no such thing as a reserved word in Funky. */
120 if (function_name
== "if")
121 function_type
= if__
;
122 else if (function_name
== "defined")
123 function_type
= defined__
;
125 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__
);
128 { /* we know this function - now call it */ }
130 assert(curr
->value
.id() == comma_separated_list_id__
);
131 TreeIterator
end(curr
->children
.end());
132 TreeIterator
curr_arg(curr
->children
.begin());
133 unsigned int argument_index(0);
134 bool evaluate_second(true);
135 bool evaluate_third(true);
136 if (function_type
== if__
&& std::distance(curr_arg
, end
) != 6 /* counting commas */)
137 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_count_mismatch__
, 3, std::distance(curr_arg
, end
) / 2);
139 { /* all is well so far */ }
140 if (function_type
== defined__
&& std::distance(curr_arg
, end
) != 2 /* counting commas */)
141 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_count_mismatch__
, 1, std::distance(curr_arg
, end
) / 2);
143 { /* all is well so far */ }
146 assert(curr_arg
== end
|| *(curr_arg
->value
.begin()) == ',');
150 assert(curr_arg
!= end
);
151 if ((argument_index
== 1 && !evaluate_second
) ||
152 (argument_index
== 2 && !evaluate_third
))
153 { /* skip this argument */ }
156 switch (curr_arg
->value
.id().to_long())
159 if (function_type
== defined__
)
160 args
.push_back(1); // literals are always defined
162 args
.push_back(boost::lexical_cast
< typename
Arguments::value_type
>(std::string(curr_arg
->value
.begin(), curr_arg
->value
.end())));
164 case parameter_id__
:
166 std::string
parameter_id(std::string(curr_arg
->value
.begin(), curr_arg
->value
.end()));
167 assert(parameter_id
.size() > 1);
168 if (parameter_id
!= "@@")
170 unsigned int index(boost::lexical_cast
<unsigned int>(parameter_id
.substr(1)));
171 if (stack_
.top().second
->size() <= index
&& function_type
!= defined__
)
172 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::argument_out_of_range__
, stack_
.top().second
->size() - 1, index
);
173 else if (function_type
== defined__
&& stack_
.top().second
->size() <= index
)
175 else if (function_type
== defined__
)
178 args
.push_back(stack_
.top().second
->at(index
));
182 if (function_type
== defined__
)
183 args
.push_back(!stack_
.top().second
->empty());
184 else // copy all arguments
185 std::copy(stack_
.top().second
->begin(), stack_
.top().second
->end(), std::back_inserter(args
));
189 case statement_id__
:
191 // can't pass a statement to defined
192 if (function_type
== defined__
)
193 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unexpected_statement__
);
195 { /* not a defined call */ }
196 Arguments
temp_args((*this)(*curr_arg
, stack_
.top().second
).value_
);
197 std::copy(temp_args
.begin(), temp_args
.end(), std::back_inserter(args
));
200 case function_name_id__
: // a function call without arguments
201 // can't pass a function call to defined
202 if (function_type
== defined__
)
203 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unexpected_statement__
);
205 { /* not a defined call */ }
207 std::string
function_to_call(curr_arg
->value
.begin(), curr_arg
->value
.end());
208 // look up the function
209 typename StoredFunctions
< Arguments
>::const_iterator
which(functions_
.find(function_to_call
));
210 if (which
== functions_
.end() && function_to_call
!= "shift")
211 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::unknown_function__
);
212 else if (function_to_call
== "shift")
214 if (stack_
.top().second
->empty())
215 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::no_more_arguments__
);
218 args
.push_back(stack_
.top().second
->at(0));
219 stack_
.top().second
->erase(stack_
.top().second
->begin());
225 Arguments
returned_args(which
->second
->call(*this, &no_args
));
226 std::copy(returned_args
.begin(), returned_args
.end(), std::back_inserter(args
));
231 throw std::logic_error("Unexpected node type");
236 if (function_type
== if__
&& argument_index
== 1)
238 // this is where we make the choice whether or not to evaluate the next, second argument
240 evaluate_second
= false;
242 evaluate_third
= false;
247 } while (curr_arg
!= end
);
248 if (function_type
!= if__
&& function_type
!= defined__
)
249 value_
= which
->second
->call(*this, &args
);
251 value_
= Arguments(1, args
.back());
256 const StoredFunctions
< Arguments
> & functions_
;