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.
35 #include <boost/spirit.hpp>
36 #include <boost/spirit/tree/ast.hpp>
37 #include <boost/format.hpp>
38 #include <boost/bind.hpp>
39 #include <boost/function.hpp>
40 #include <boost/lexical_cast.hpp>
41 #include <boost/shared_ptr.hpp>
42 #include <loki/ScopeGuard.h>
45 #include "Exceptions/FunctionCallError.h"
46 #include "Exceptions/ParseError.h"
47 #include "Private/StoredFunction.h"
48 #include "Private/StoredFunctions.h"
49 #include "Private/Grammar.h"
50 #include "Private/Evaluator.h"
51 #include "Private/FunctionPointer.h"
52 #include "Private/FunctionPointer2.h"
53 #include "Private/ParsedFunction.h"
54 #include "Private/Language.h"
55 #include "Private/extractFunctions__.h"
59 using namespace Private
;
63 // This is the type of a node in the parse tree
64 typedef boost::spirit::tree_node
< boost::spirit::node_val_data
<> > Node
;
66 // the value to return to the caller, from run() or eval()
68 // the parameters passed to the script
69 Arguments parameters_
;
71 // the functions installed by either the user or the parser. This is the equivalent of a symbol table
72 StoredFunctions
< Arguments
> functions_
;
73 // the main function - the last statement in the script
79 grammar_(new Grammar
< double >())
81 // install the built-in functions
82 installFunction("test", Function(boost::bind(&Language::test__
< double >, _1
)), 1);
83 installFunction("or", Function(boost::bind(&Language::or__
< double >, _1
)), 2);
84 installFunction("and", Function(boost::bind(&Language::and__
< double >, _1
)), 2);
85 installFunction("not", Function(boost::bind(&Language::not__
< double >, _1
)), 1);
86 installFunction("add", Function(boost::bind(&Language::add__
< double >, _1
)), 2);
87 installFunction("neg", Function(boost::bind(&Language::neg__
< double >, _1
)), 1);
88 installFunction("mul", Function(boost::bind(&Language::mul__
< double >, _1
)), 2);
89 installFunction("div", Function(boost::bind(&Language::div__
< double >, _1
)), 2);
98 void Funky::parse(const std::string
& program_text
)
100 boost::spirit::tree_parse_info
<> parse_result
;
104 parse_result
= boost::spirit::ast_parse(program_text
.c_str(), *grammar_
, boost::spirit::space_p
);
106 catch (const boost::spirit::parser_error
< Exceptions::ParseError::Reason
> & e
)
108 throw Exceptions::ParseError(e
.descriptor
, static_cast< unsigned int >(e
.where
- program_text
.c_str()));
110 if (!parse_result
.full
)
112 throw Exceptions::ParseError(Exceptions::ParseError::incomplete_parse__
, parse_result
.length
);
115 { /* all is well so far */ }
117 /* Once the text is parsed, we have a parse tree. We now need to extract,
118 * from that tree, any functions we may have found in order to put them in
119 * the symbol table (data_->functions_) and the last statement, which is
120 * the one that will be run by run(), which we put in data_->main_. */
121 extractFunctions__(parse_result
, data_
->functions_
, data_
->main_
);
124 double Funky::run(const Arguments
& _arguments
/* = Arguments()*/) const
126 Arguments
arguments(_arguments
);
127 Evaluator
< Arguments
> evaluator( data_
->functions_
);
128 evaluator(data_
->main_
, &arguments
);
129 if (evaluator
.value_
.size() != 1)
130 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::return_value_count_mismatch__
, 1, static_cast< int >(evaluator
.value_
.size()));
132 { /* all is well */ }
133 return evaluator
.value_
.front();
136 double Funky::run(const boost::any
& user
, const Arguments
& _arguments
/* = Arguments()*/)
138 Arguments
arguments(_arguments
);
139 Evaluator
< Arguments
> evaluator( data_
->functions_
, user
);
140 evaluator(data_
->main_
, &arguments
);
141 if (evaluator
.value_
.size() != 1)
142 throw Exceptions::FunctionCallError(Exceptions::FunctionCallError::return_value_count_mismatch__
, 1, static_cast< int >(evaluator
.value_
.size()));
144 { /* all is well */ }
145 return evaluator
.value_
.front();
148 double Funky::eval(const std::string
& program_text
, const Arguments
& arguments
)
151 return run(arguments
);
154 double Funky::eval(const std::string
& program_text
, const boost::any
& user
, const Arguments
& arguments
)
157 return run(user
, arguments
);
160 void Funky::installFunction(const std::string
& function_name
, const Function
& function
, int expected_args
/* = any__*/)
162 StoredFunctions
< Arguments
>::iterator
where(data_
->functions_
.find(function_name
));
163 if (where
!= data_
->functions_
.end())
164 data_
->functions_
.erase(where
);
166 { /* not a duplicate definition */ }
168 data_
->functions_
.insert(StoredFunctions
< Arguments
>::value_type(function_name
, boost::shared_ptr
< StoredFunction
< Arguments
> >(new FunctionPointer
< Arguments
>(function
, expected_args
))));
171 void Funky::installFunction(const std::string
& function_name
, const MultiReturnFunction
& function
, int expected_args
/* = any__*/, int expected_returns
/* = any__*/)
173 StoredFunctions
< Arguments
>::iterator
where(data_
->functions_
.find(function_name
));
174 if (where
!= data_
->functions_
.end())
175 data_
->functions_
.erase(where
);
177 { /* not a duplicate definition */ }
179 data_
->functions_
.insert(StoredFunctions
< Arguments
>::value_type(function_name
, boost::shared_ptr
< StoredFunction
< Arguments
> >(new FunctionPointer
< Arguments
>(function
, expected_args
, expected_returns
))));
182 void Funky::installFunction2(const std::string
& function_name
, const Function2
& function
, int expected_args
/* = any__*/)
184 StoredFunctions
< Arguments
>::iterator
where(data_
->functions_
.find(function_name
));
185 if (where
!= data_
->functions_
.end())
186 data_
->functions_
.erase(where
);
188 { /* not a duplicate definition */ }
190 data_
->functions_
.insert(StoredFunctions
< Arguments
>::value_type(function_name
, boost::shared_ptr
< StoredFunction
< Arguments
> >(new FunctionPointer2
< Arguments
>(function
, expected_args
))));
193 void Funky::installFunction2(const std::string
& function_name
, const MultiReturnFunction2
& function
, int expected_args
/* = any__*/, int expected_returns
/* = any__*/)
195 StoredFunctions
< Arguments
>::iterator
where(data_
->functions_
.find(function_name
));
196 if (where
!= data_
->functions_
.end())
197 data_
->functions_
.erase(where
);
199 { /* not a duplicate definition */ }
201 data_
->functions_
.insert(StoredFunctions
< Arguments
>::value_type(function_name
, boost::shared_ptr
< StoredFunction
< Arguments
> >(new FunctionPointer2
< Arguments
>(function
, expected_args
, expected_returns
))));
204 void Funky::removeFunction(const std::string
& function_name
)
206 StoredFunctions
< Arguments
>::iterator
where(data_
->functions_
.find(function_name
));
207 if (where
!= data_
->functions_
.end())
208 data_
->functions_
.erase(where
);
210 { /* function not found - no-op */ }