Compare commits

..

101 Commits

Author SHA1 Message Date
Jason Turner
d2d752ecd4 Fix registration of module loading functions 2009-10-19 14:00:48 +00:00
Jason Turner
a18c701866 Fix type-shifting of bind_first for free function pointer types 2009-10-16 15:49:46 +00:00
Jason Turner
9871604a48 Make sure example.cpp compilable with new setup 2009-10-15 15:55:16 +00:00
Jason Turner
b1d12fdc91 Further updates to the new bound function support, plus general cleanup of how it is used 2009-10-15 15:27:16 +00:00
Jason Turner
24e717d532 Fix "bind_first" for non member functions 2009-10-14 22:42:45 +00:00
Jason Turner
1568fedebd Reduce # of required versions for bound_fun and enhance it to work with non-member functions 2009-10-14 17:19:42 +00:00
Jonathan Turner
c88578d537 Add another unit test for operator overloading 2009-10-14 14:00:22 +00:00
Jonathan Turner
9827345213 Fix Id Literals so that they are keyed off an Id search. This allows us to add operator overloading on the parse side. 2009-10-14 13:51:35 +00:00
Jonathan Turner
c51d14fb13 Add some missing unit tests for number formats and block starting 2009-10-14 12:25:21 +00:00
Jason Turner
480761c1f7 Add bound_fun helper and put it to use cleaning up the engine bootstrapping 2009-10-14 02:34:09 +00:00
Jonathan Turner
12e909d9aa Add bit shifting operators 2009-10-13 03:35:01 +00:00
Jason Turner
b1e892487f Enhance "is_type" to be more accurate and to work with Dynamic_Object types 2009-10-13 03:31:56 +00:00
Jason Turner
720eabcb16 Impliment range find functions and add unit test for contains and find. 2009-10-13 02:05:18 +00:00
Jason Turner
1fde71f3f4 Add type generic comparison operations "eq", "gt", and "lt" and port the "contains" operation to use it 2009-10-13 00:18:59 +00:00
Jonathan Turner
90f8b77171 Added .contains() to ranges 2009-10-11 20:02:21 +00:00
Jonathan Turner
315d7521a7 Clean up warnings. Add simple blocks. 2009-10-08 03:01:19 +00:00
Jonathan Turner
ff177b5eaf Add octal support 2009-10-06 21:17:23 +00:00
Jonathan Turner
46fd7e9a58 Add hex value parsing support 2009-10-06 16:04:05 +00:00
Jason Turner
edd274ccce Fix some more obscure warnings 2009-10-06 02:26:47 +00:00
Jonathan Turner
a5b2ec3006 Start code cleanups by moving chaiscript common structures into their own file. 2009-09-23 05:00:14 +00:00
Jason Turner
cd3c0d4fd7 Update property page to something more in line with normal boost installs. 2009-09-23 00:42:08 +00:00
Jason Turner
3bdd79a3fd Correct Windows unicode build issues. 2009-09-22 23:03:16 +00:00
Jason Turner
b04e01cda7 Ensure that __EVAL__ is in the list of loaded files and be smarter about accessing it 2009-09-22 21:06:02 +00:00
Jason Turner
bad5384c96 Fix multi-file compilation issues 2009-09-22 20:59:10 +00:00
Jason Turner
443902f787 Reduce overhead necessary for internal_eval. Desirable due to the use of "eval" during cloning operations 2009-09-22 01:58:16 +00:00
Jason Turner
d3cdd6959d Add unit tests for range lookups 2009-09-22 01:36:13 +00:00
Jason Turner
9762e15460 Fix some range/retro issues and update the visual studio files 2009-09-22 01:23:02 +00:00
Jonathan Turner
33897e2c0f Add unit tests for multiline and inner outer loops 2009-09-21 17:31:10 +00:00
Jonathan Turner
9528e44b88 Add unit tests for multiline and inner outer loops 2009-09-21 17:30:55 +00:00
Jonathan Turner
03746e7606 Add keywords for NaN and Infinity 2009-09-21 16:50:30 +00:00
Jason Turner
50eace16da Allow "Module" to contain chaiscript snippets to be executed when a module is initialized. Update dynamic_object to use the new feature to clean up some of the _prelude.hpp 2009-09-21 03:07:01 +00:00
Jason Turner
8241e46680 Further refine how clone calls are dynamically generated, to avoid accidentally matching when we should not 2009-09-20 21:49:53 +00:00
Jason Turner
160f64e9c2 Enabled short hand for adding new methods to existing C++ types 2009-09-20 21:32:39 +00:00
Jason Turner
593c6c68ee Port "retro" to use the new built in object typing, add unit test for retro'ing a retro 2009-09-20 03:50:25 +00:00
Jason Turner
991753a492 Add support for cloning of dynamic objects 2009-09-19 23:12:56 +00:00
Jason Turner
7cdd772f2b Add const correctness for proxy functions. Add unit tests for function variable assignment scenarios 2009-09-19 21:13:12 +00:00
Jonathan Turner
c5f837fd19 Added 'finally' to try/catch block 2009-09-19 18:12:22 +00:00
Jonathan Turner
7c244d25b5 Add support for chai objects by adding methods and attrs 2009-09-19 15:32:12 +00:00
Jonathan Turner
18fc4d419f Fix to catch block handling that would have lost the scope of the boost::ref of the exception 2009-09-19 13:40:48 +00:00
Jonathan Turner
813fa055a3 Added guarded exception catches 2009-09-19 13:30:11 +00:00
Jason Turner
6a47846b84 Add runtime_error support, for throwing a normal std::exception. Also, move bootstrap for Dynamic_Object into its proper place. 2009-09-19 12:15:17 +00:00
Jason Turner
b0041217b0 initial checkin of dynamic object support with example usage in example.cpp 2009-09-19 02:36:27 +00:00
Jonathan Turner
fedcd28ecc Add exception unit test 2009-09-19 02:21:36 +00:00
Jonathan Turner
b17c6b9748 Add support for std::exception and what() 2009-09-18 22:26:07 +00:00
Jonathan Turner
204d379176 Fix default cmake build to use readline and gdb. Add simple try/catch/throw exceptions 2009-09-18 22:04:07 +00:00
Jason Turner
a754ce9eb6 Initial check in of code analysis tool 2009-09-16 01:46:04 +00:00
Jonathan Turner
99b5f46a9e Fix type in help. 2009-09-15 20:32:16 +00:00
Jason Turner
394d8c3bf6 Allow the user to choose the build type using CMAKE_BUILD_TYPE by eliminating the overrides in the CMakeLists.txt file 2009-09-15 02:53:23 +00:00
Jason Turner
4bdbcf30ff Move std::list<> support from main.cpp into a module, stl_extra.cpp, to better allow for measuring of core compile times / performance. 2009-09-15 01:30:51 +00:00
Jonathan Turner
63de0fd33c Add a couple more in-string eval unit tests to check for proper escaping 2009-09-13 12:53:12 +00:00
Jonathan Turner
0fbb7c44bd Add some unit tests for in-string eval 2009-09-12 14:55:14 +00:00
Jonathan Turner
5092713876 Add in-string eval 2009-09-12 14:52:46 +00:00
Jason Turner
f369afed77 Decrease compile times by 30% and runtimes by 10% by eliminating use of boost::bind during function dispatch 2009-09-10 03:44:42 +00:00
Jonathan Turner
f23f0edc70 Fix parser to handle shortform equations (fix bad operator parsing). Add back lines to prelude for line numbers 2009-09-09 14:11:03 +00:00
Jason Turner
daee00da95 Minor performance enhancement for caching function and cleanup of minor windows warning in same function. 2009-09-09 13:17:20 +00:00
Jason Turner
e2cdac0406 Decrease compilation time by removing "Retro" from c++ compiled and making a chaiscript version instead 2009-09-09 03:11:47 +00:00
Jason Turner
cc44ec99ba Fix reversed logic in printing output during eval 2009-09-08 23:39:34 +00:00
Jonathan Turner
1bf3b1ed37 Couple changes for module loading in mingw 2009-09-08 21:22:37 +00:00
Jason Turner
f7b530ebae Quick fix to (hopefully) module support on mingw 2009-09-08 19:21:11 +00:00
Jason Turner
b185e2e792 Make Type_Info internal data private and provide more rigorous definitions for comparisions of objects 2009-09-08 13:31:14 +00:00
Jonathan Turner
73ec2abd43 Add unit test script for windows 2009-09-08 02:22:49 +00:00
Jonathan Turner
cfee4c6bc1 Bugfix: cached the wrong boolean value. Fixed. 2009-09-08 02:15:41 +00:00
Jonathan Turner
2d4b9c0d93 Another Touchup fix to CMakeLists.txt for cleanliness 2009-09-07 21:25:10 +00:00
Jonathan Turner
f522d3697c Touchup fix to CMakeLists.txt for cleanliness 2009-09-07 21:09:18 +00:00
Jonathan Turner
48e96b2f3b Add readline support to eval. 2009-09-07 20:52:31 +00:00
Jason Turner
798908f127 Add loadable module support for ms Visual C++ and fix visual studio specific type identification problems, (while making the C++ more correct) 2009-09-07 17:05:57 +00:00
Jonathan Turner
7e3127549f Added simple const value caching. Fix CMake to default back to debug mode 2009-09-07 15:48:32 +00:00
Jonathan Turner
4713325877 Touchup to cmake project file to prevent error msg in OS X 2009-09-07 14:13:28 +00:00
Jason Turner
7cc6a3cab9 Add support for loadable modules on POSIX systems 2009-09-06 23:33:03 +00:00
Jonathan Turner
cba5731576 Fixing the last of the const change issues 2009-09-06 02:55:39 +00:00
Jonathan Turner
b3656c95f5 Correcting unit tests that are inc/dec temporaries. This is no longer allowed 2009-09-06 02:50:36 +00:00
Jonathan Turner
e9539dfee2 BROKEN./run_unit_tests.sh ! This is to help repair unit tests broken in move to consts. Should be fixed shortly. 2009-09-06 02:24:46 +00:00
Jason Turner
4b40812e26 Add const_var helper function for making const values. 2009-09-06 02:09:19 +00:00
Jason Turner
ef8cd1f591 Add more robust support for handling of const ptr values 2009-09-05 23:46:21 +00:00
Jason Turner
46cdb89921 Add missing chaiscript_threading.hpp 2009-09-05 13:10:27 +00:00
Jason Turner
3094ff6e3b Made thread saftey a compilation option for performance and dependencies reasons 2009-09-05 00:16:46 +00:00
Jason Turner
4d42d6ff33 Add shared objects that can be used by all threads at their root scope only 2009-09-03 11:42:23 +00:00
Jason Turner
a427d2c1a9 Correct function pointer casts to more correct static_cast<>() 2009-09-03 00:15:56 +00:00
Jason Turner
efb7a8d453 Create local thread caches of registered function objects to reduce thread contention 2009-09-02 02:28:38 +00:00
Jason Turner
6c4872eae9 Initial check in of multithreaded support for chaiscript 2009-08-31 19:50:41 +00:00
Jason Turner
ff639a267d Shave a few cycles off by reducing copies and assignments of objects in eval 2009-08-30 02:24:11 +00:00
Jason Turner
94e4b671f3 Make sure to invalidate the cache when a new function name is added 2009-08-30 01:06:21 +00:00
Jason Turner
096c8aab50 Provide for caching of objects in the dispatch get get_object side. Also, update chaiscript_eval to not explicitly add a new stack object to each scope as it is created 2009-08-30 00:48:17 +00:00
Jason Turner
89186a86c8 speed up operator calls by about 10% by reducing Proxy_Function copies and such 2009-08-29 19:19:31 +00:00
Jason Turner
c8c1c65e8c Add std::list support 2009-08-29 14:00:07 +00:00
Jonathan Turner
c5e1d5fa20 Add ref equal unit test 2009-08-27 15:03:49 +00:00
Jonathan Turner
91011695f0 Allow simple multiline commands in arg list and container arg list 2009-08-26 20:34:32 +00:00
Jason Turner
3a951cea99 Extend the reserved object name registration to include some missing values such as break and return and such 2009-08-26 02:21:41 +00:00
Jonathan Turner
8620f4eaf9 Fix for issue 23, makes for and while loops live in their own deeper scope 2009-08-26 02:02:41 +00:00
Jonathan Turner
59ecf32f9b Add Eval_Error end extents and reserved word errors 2009-08-25 01:10:28 +00:00
Jason Turner
541e453098 check in of reserved word handling 2009-08-25 00:36:02 +00:00
Jason Turner
0b780593a6 Make for better error messages when a clone fails 2009-08-22 13:55:06 +00:00
Jason Turner
2e7c5f413e Cleanup get_function implementation 2009-08-21 22:51:12 +00:00
Jonathan Turner
7e5b7cbd7a Switch get_function to default to not doing object lookup. Correct method eval to maintain method lambda syntax. Add unit test for method lambda 2009-08-21 20:05:05 +00:00
Jonathan Turner
c539e0b458 Add unittest for 'use' feature 2009-08-21 18:26:34 +00:00
Jason Turner
1f011f3d5b Add "use" function for loading chai files from inside of ChaiScript and fix potential memory bug with filename const char * pointers being passed around 2009-08-21 03:33:57 +00:00
Jason Turner
a136236179 Fix dispatch for const boost::shared_ptr<> & parameters for functions, add a test to example.cpp and fix some issues with building example.cpp 2009-08-20 21:35:56 +00:00
Jonathan Turner
8840f06053 Allow floating point numbers without a zero before the decimal point 2009-08-20 14:50:13 +00:00
Jason Turner
00e4de774f Move "fun_helper" into detail namespace 2009-08-09 19:12:01 +00:00
Jason Turner
bc3a17b3b7 Port VC++ fix from last rev back to Linux 2009-08-09 18:42:32 +00:00
Jason Turner
4a57efde25 Correct bug with bootstrapping of Map type on windows. Also, make it easier to specify the type of a function being added at the time it is being added. 2009-08-09 16:49:14 +00:00
106 changed files with 3750 additions and 1100 deletions

View File

@@ -2,23 +2,43 @@ cmake_minimum_required(VERSION 2.6)
project(chaiscript)
SET (CMAKE_BUILD_TYPE gdb)
SET (CMAKE_C_FLAGS_GDB " -Wall -ggdb")
SET (CMAKE_CXX_FLAGS_GDB " -Wall -ggdb")
FIND_LIBRARY(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
#SET (CMAKE_BUILD_TYPE rel)
#SET (CMAKE_C_FLAGS_REL " -Wall -O3")
#SET (CMAKE_CXX_FLAGS_REL " -Wall -O3")
MESSAGE(STATUS "Detecting readline support")
if (READLINE_LIBRARY)
MESSAGE(STATUS "Found: ${READLINE_LIBRARY}")
SET (READLINE_LIB readline)
SET (READLINE_FLAG " -DREADLINE_AVAILABLE")
else(READLINE_LIBRARY)
MESSAGE(STATUS "Not Found")
SET (READLINE_LIB )
SET (READLINE_FLAG )
endif(READLINE_LIBRARY)
SET (CMAKE_C_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
SET (CMAKE_CXX_FLAGS_REL " -Wall -O3 ${READLINE_FLAG}")
SET (CMAKE_C_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
SET (CMAKE_CXX_FLAGS " -Wall -ggdb ${READLINE_FLAG}")
include_directories(include)
find_package(Boost 1.36.0)
find_package(Boost 1.36.0 COMPONENTS thread)
if (Boost_FOUND)
include_directories(${Boost_INCLUDE_DIRS})
add_executable(chaiscript_eval src/main.cpp)
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.cpp)
target_link_libraries(chaiscript_eval ${Boost_LIBRARIES})
target_link_libraries(chaiscript_eval dl ${Boost_LIBRARIES} ${READLINE_LIB})
add_library(test MODULE src/test_module.cpp)
target_link_libraries(test ${Boost_LIBRARIES})
add_library(stl_extra MODULE src/stl_extra.cpp)
target_link_libraries(stl_extra ${Boost_LIBRARIES})
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
else(Boost_FOUND)
message(FATAL_ERROR "Can not find Boost")
endif(Boost_FOUND)

View File

@@ -0,0 +1,43 @@
function analyze_data
{
echo -n "$1," >> $2
awk 'END {printf "%s,", $1}' r$1-codesize.out >> $2
awk '{printf "%s,", $1}' r$1-numunittests.out >> $2
awk 'END {printf "%s,", $1}' r$1-unittestsoutput.out >> $2
awk '{printf "%s,", $1}' r$1-debugbinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-debugbuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-debugprofiletime.out >> $2
awk '{printf "%s,", $1}' r$1-releasebinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releasebuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releasemodulesbuildtime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releaseprofiletime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-releaseunittestruntime.out >> $2
if [ -x r$1-threadfreebinarysize.out ]
then
awk '{printf "%s,", $1}' r$1-threadfreebinarysize.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-threadfreeprofiletime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-1threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-2threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-4threadruntime.out >> $2
awk 'NR>1{exit} 1 {printf "%s,", $2}' r$1-8threadruntime.out >> $2
else
echo -n ",,,,,," >> $2
fi
awk -F "\n" 'NR>1{exit} 1 {printf "\"%s\"\n", $1}' r$1-revisionlog.out >> $2
}
filename=output-$1-$2.csv
echo "Revision, LOC, Num Unit Tests, Successful Unit Tests, Debug Binary Size, Debug Build Time, Debug Profile Time, Release Binary Size, Release Core Build Time, Release Modules Build Time, Release Profile Time, Release Unit Tests Time, Threadless Binary Size, Threadless Profile Time, 1 Thread Profile Time, 2 Threads Profile Time, 4 Threads Profile Time, 8 Threads Profile Time, Revision Log" > $filename
for i in `seq $1 $2`
do
analyze_data $i $filename
done

View File

@@ -0,0 +1,81 @@
function run_test
{
echo "****Getting r$1 from SVN"
svn export --quiet -r$1 http://chaiscript.googlecode.com/svn/trunk chaiscript-r$1
pushd chaiscript-r$1
echo "****Getting svn revision log"
svn propget svn:log --revprop -r$1 http://chaiscript.googlecode.com/svn/trunk > ../r$1-revisionlog.out
echo "****Editing CMakeLists.txt to allow for build type switching"
# Clean up CMakeLists.txt so that we can set the build type at configure time
sed -i -e "s/SET (CMAKE_BUILD_TYPE.*//" CMakeLists.txt
echo "****Compiling Debug Build"
cmake -D CMAKE_BUILD_TYPE=Debug CMakeLists.txt
/usr/bin/time -p make chaiscript_eval 2> ../r$1-debugbuildtime.out
echo "****Analyzing Debug Build"
/usr/bin/time -p ./chaiscript_eval ../profile.chai 2>../r$1-debugprofiletime.out
ls -s --block-size=1 ./chaiscript_eval > ../r$1-debugbinarysize.out
make clean
echo "****Compiling Release Build"
cmake -D CMAKE_BUILD_TYPE=Release CMakeLists.txt
/usr/bin/time -p make chaiscript_eval 2> ../r$1-releasebuildtime.out
echo "****Analyzing Release Build"
/usr/bin/time -p ./chaiscript_eval ../profile.chai 2>../r$1-releaseprofiletime.out
ls -s --block-size=1 ./chaiscript_eval > ../r$1-releasebinarysize.out
echo "****Analyzing Code Size"
find ./include -name "*.hpp" | xargs wc > ../r$1-codesize.out
echo "****Building Remaining Modules"
/usr/bin/time -p make 2> ../r$1-releasemodulesbuildtime.out
echo "****Running unit tests"
/usr/bin/time -p ./run_unit_tests.sh 2> ../r$1-releaseunittestruntime.out > ../r$1-unittestsoutput.out
echo "****Counting number of unit tests"
find unittests/ -name "*.chai" | wc | awk '{print $1}' > ../r$1-numunittests.out
echo "****Running multithreaded tests"
if [ -e src/multithreaded.cpp ]
then
# Run multithreaded tests
echo "****Building multithreaded test"
pushd src
g++ multithreaded.cpp -lboost_thread-mt -ldl -omultithreaded -I../include -O3
echo "****Testing 1 thread runtime"
/usr/bin/time -p ./multithreaded 1 2> ../../r$1-1threadruntime.out
echo "****Testing 2 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 2> ../../r$1-2threadruntime.out
echo "****Testing 4 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 1 1 2> ../../r$1-4threadruntime.out
echo "****Testing 8 thread runtime"
/usr/bin/time -p ./multithreaded 1 1 1 1 1 1 1 1 2> ../../r$1-8threadruntime.out
echo "****Compiling thread-free version"
g++ main.cpp -ldl -othreadfree -I../include -O3 -DCHAISCRIPT_NO_THREADS
echo "****Analyzing thread-free version"
/usr/bin/time -p ./threadfree ../../profile.chai 2>../../r$1-threadfreeprofiletime.out
ls -s --block-size=1 ./threadfree > ../../r$1-threadfreebinarysize.out
popd
else
echo "Multithreaded test non-existent"
fi
popd
}
for i in `seq $1 $2`
do
run_test $i
done

View File

@@ -0,0 +1,15 @@
var total = 0
for (var i = 0.0; i < 10000.0; i += 0.1) {
total += int(double(i) + int(10));
if (i < 9000.0)
{
total += double(11);
if (i > double(4000.0))
{
total += double(10);
}
}
}
print(total)

View File

@@ -21,113 +21,13 @@
#include "dispatchkit/bootstrap.hpp"
#include "dispatchkit/bootstrap_stl.hpp"
#include "dispatchkit/function_call.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 }; };
#include "dispatchkit/dynamic_object.hpp"
/**
* 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 during parsing or evaluation
*/
struct Eval_Error : public std::runtime_error {
std::string reason;
File_Position position;
const char *filename;
Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
std::runtime_error("Error: \"" + why + "\" " +
(std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), position(where), filename(fname)
{ }
Eval_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Error: \"" + why + "\" " +
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
boost::lexical_cast<std::string>(where->start.column) + ")"),
reason(why), position(where->start), filename(where->filename) {
}
virtual ~Eval_Error() throw() {}
};
/**
* Special type for returned values
*/
struct Return_Value {
Boxed_Value retval;
TokenPtr location;
Return_Value(const 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) { }
};
}
#ifdef BOOST_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
#include "language/chaiscript_eval.hpp"
#include "language/chaiscript_engine.hpp"

View File

@@ -0,0 +1,73 @@
#ifndef __chaiscript_threading_hpp__
#define __chaiscript_threading_hpp__
#ifndef CHAISCRIPT_NO_THREADS
#include <boost/thread.hpp>
#else
#warning "ChaiScript is compiling without thread safety."
#endif
namespace chaiscript
{
namespace threading
{
#ifndef CHAISCRIPT_NO_THREADS
template<typename T>
class Thread_Storage
{
public:
~Thread_Storage()
{
m_thread_storage.reset();
}
inline T *operator->() const
{
if (!m_thread_storage.get())
{
m_thread_storage.reset(new T());
}
return m_thread_storage.get();
}
inline T &operator*() const
{
return *(this->operator->());
}
private:
mutable boost::thread_specific_ptr<T> m_thread_storage;
};
#else
template<typename T>
class Thread_Storage
{
public:
inline T *operator->() const
{
return &obj;
}
inline T &operator*() const
{
return obj;
}
private:
mutable T obj;
};
#endif
}
}
#endif

View File

@@ -0,0 +1,65 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#include <boost/preprocessor/arithmetic/inc.hpp>
#define param(z,n,text) BOOST_PP_CAT(text, BOOST_PP_INC(n))
#ifndef BOOST_PP_IS_ITERATING
#ifndef __bind_first_hpp__
#define __bind_first_hpp__
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#define BOOST_PP_ITERATION_LIMITS ( 0, 8 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/bind_first.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
# define m BOOST_PP_INC(n)
namespace chaiscript
{
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)), const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret, typename O, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param) >
boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>
bind_first(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const, const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(Ret (*f)(BOOST_PP_ENUM_PARAMS(m, Param)), const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
template<typename Ret,typename O BOOST_PP_COMMA_IF(m) BOOST_PP_ENUM_PARAMS(m, typename Param) >
boost::function<Ret (BOOST_PP_ENUM(n, param, Param))>
bind_first(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(m, Param))> &f, const O &o)
{
return boost::bind(f, o BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM(n, param, _));
}
}
#endif

View File

@@ -8,6 +8,7 @@
#define __bootstrap_hpp__
#include "dispatchkit.hpp"
#include "dynamic_object.hpp"
#include "register_function.hpp"
namespace chaiscript
@@ -49,6 +50,18 @@ namespace chaiscript
return p1 % p2;
}
template<typename Ret, typename P1, typename P2>
Ret shift_left(P1 p1, P2 p2)
{
return p1 << p2;
}
template<typename Ret, typename P1, typename P2>
Ret shift_right(P1 p1, P2 p2)
{
return p1 >> p2;
}
template<typename P1, typename P2>
P1 &assign(P1 &p1, const P2 &p2)
{
@@ -482,18 +495,6 @@ namespace chaiscript
return boost::lexical_cast<std::string>(i);
}
/**
* Boolean specialization of internal to_string function
*/
template<> std::string to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
/**
* Internal function for converting from a string to a value
@@ -532,22 +533,39 @@ namespace chaiscript
* function variables.
*/
template<typename Type>
boost::shared_ptr<Type> shared_ptr_clone(boost::shared_ptr<Type> f)
boost::shared_ptr<Type> shared_ptr_clone(const boost::shared_ptr<Type> &p)
{
return f;
return p;
}
/**
* Specific version of shared_ptr_clone just for Proxy_Functions
*/
template<typename Type>
boost::shared_ptr<typename boost::remove_const<Type>::type>
shared_ptr_unconst_clone(const boost::shared_ptr<typename boost::add_const<Type>::type> &p)
{
return boost::const_pointer_cast<typename boost::remove_const<Type>::type>(p);
}
/**
* Assignment function for shared_ptr objects, does not perform a copy of the
* object pointed to, instead maintains the shared_ptr concept.
* Similar to shared_ptr_clone. Used for Proxy_Function.
*/
template<typename Type>
Boxed_Value ptr_assign(Boxed_Value lhs, boost::shared_ptr<Type> rhs)
Boxed_Value ptr_assign(Boxed_Value lhs, const boost::shared_ptr<typename boost::add_const<Type>::type> &rhs)
{
lhs.assign(Boxed_Value(rhs));
return lhs;
if (lhs.is_unknown()
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
{
lhs.assign(Boxed_Value(rhs));
return lhs;
} else {
throw bad_boxed_cast("type mismatch in pointer assignment");
}
}
/**
@@ -616,9 +634,9 @@ namespace chaiscript
throw arity_error(params.size(), 2);
}
Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(Proxy_Function(new Bound_Function(f,
return Boxed_Value(Const_Proxy_Function(new Bound_Function(f,
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
}
@@ -633,17 +651,39 @@ namespace chaiscript
throw arity_error(params.size(), 1);
}
Proxy_Function f = boxed_cast<Proxy_Function >(params[0]);
Const_Proxy_Function f = boxed_cast<Const_Proxy_Function>(params[0]);
return Boxed_Value(f->call_match(std::vector<Boxed_Value>(params.begin() + 1, params.end())));
}
static void throw_exception(const Boxed_Value &bv) {
throw bv;
}
static boost::shared_ptr<Dispatch_Engine> bootstrap2(boost::shared_ptr<Dispatch_Engine> e = boost::shared_ptr<Dispatch_Engine> (new Dispatch_Engine()))
{
e->add(user_type<void>(), "void");
return e;
}
static std::string what(const std::exception &e)
{
return e.what();
}
/**
* Boolean specialization of internal to_string function
*/
static std::string bool_to_string(bool b)
{
if (b)
{
return "true";
} else {
return "false";
}
}
public:
/**
* perform all common bootstrap functions for std::string, void and POD types
@@ -655,14 +695,29 @@ namespace chaiscript
m->add(user_type<Boxed_Value>(), "Object");
m->add(user_type<Boxed_POD_Value>(), "PODObject");
m->add(user_type<Proxy_Function>(), "function");
m->add(user_type<std::exception>(), "exception");
m->add(user_type<std::runtime_error>(), "runtime_error");
m->add(constructor<std::runtime_error (const std::string &)>(), "runtime_error");
m->add(fun(boost::function<std::string (const std::runtime_error &)>(&what)), "what");
m->add(user_type<Dynamic_Object>(), "Dynamic_Object");
m->add(constructor<Dynamic_Object (const std::string &)>(), "Dynamic_Object");
m->add(fun(&Dynamic_Object::get_type_name), "get_type_name");
m->add(fun(&Dynamic_Object::get_attrs), "get_attrs");
m->add(fun(&Dynamic_Object::get_attr), "get_attr");
m->eval("def Dynamic_Object::clone() { var new_o := Dynamic_Object(this.get_type_name()); for_each(this.get_attrs(), bind(fun(new_o, x) { new_o.get_attr(x.first) = x.second; }, new_o, _) ); return new_o; }");
basic_constructors<bool>("bool", m);
oper_assign<std::string>(m);
oper_assign<bool>(m);
m->add(fun(&to_string<const std::string &>), "internal_to_string");
m->add(fun(&to_string<bool>), "internal_to_string");
m->add(fun(&Bootstrap::bool_to_string), "internal_to_string");
m->add(fun(&unknown_assign), "=");
m->add(fun(&throw_exception), "throw");
m->add(fun(&what), "what");
bootstrap_pod_type<double>("double", m);
bootstrap_pod_type<int>("int", m);
@@ -674,6 +729,8 @@ namespace chaiscript
opers_arithmetic_pod(m);
m->add(fun(&detail::modulus<int, int, int>), "%");
m->add(fun(&detail::shift_left<int, int, int>), "<<");
m->add(fun(&detail::shift_right<int, int, int>), ">>");
m->add(fun(&print), "print_string");
m->add(fun(&println), "println_string");
@@ -681,7 +738,7 @@ namespace chaiscript
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
"bind");
m->add(fun(&shared_ptr_clone<Proxy_Function_Base>), "clone");
m->add(fun(&shared_ptr_unconst_clone<Proxy_Function_Base>), "clone");
m->add(fun(&ptr_assign<Proxy_Function_Base>), "=");
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),

View File

@@ -36,16 +36,6 @@ namespace chaiscript
{
}
Bidir_Range(typename Container::iterator itr)
: m_begin(itr), m_end(itr)
{
}
Bidir_Range(const std::pair<typename Container::iterator, typename Container::iterator> &t_p)
: m_begin(t_p.first), m_end(t_p.second)
{
}
bool empty() const
{
return m_begin == m_end;
@@ -118,20 +108,10 @@ namespace chaiscript
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<Bidir_Range<ContainerType> >(), type + "_Range");
m->add(user_type<Retro<Bidir_Range<ContainerType> > >(), type + "_Retro_Range");
m->add(user_type<typename ContainerType::iterator>(), type+"_Iterator");
copy_constructor<Bidir_Range<ContainerType> >(type + "_Range", m);
copy_constructor<Retro<Bidir_Range<ContainerType> > >(type + "_Retro_Range", m);
m->add(constructor<Bidir_Range<ContainerType> (ContainerType &)>(), "range");
m->add(constructor<Bidir_Range<ContainerType> (typename ContainerType::iterator)>(), "range");
typedef std::pair<typename ContainerType::iterator, typename ContainerType::iterator> ItrPair;
m->add(constructor<Bidir_Range<ContainerType> (const ItrPair &)>(), "range");
m->add(user_type<ItrPair>(), type+"_Iterator_Pair");
m->add(fun(&Bidir_Range<ContainerType>::empty), "empty");
m->add(fun(&Bidir_Range<ContainerType>::pop_front), "pop_front");
@@ -139,16 +119,6 @@ namespace chaiscript
m->add(fun(&Bidir_Range<ContainerType>::pop_back), "pop_back");
m->add(fun(&Bidir_Range<ContainerType>::back), "back");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::empty), "empty");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::pop_front), "pop_front");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::front), "front");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::pop_back), "pop_back");
m->add(fun(&Retro<Bidir_Range<ContainerType> >::back), "back");
m->add(constructor<Retro<Bidir_Range<ContainerType> > (const Bidir_Range<ContainerType> &)>(), "retro");
return m;
}
@@ -175,9 +145,7 @@ namespace chaiscript
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
//to throw an exception in an out of bounds condition.
m->add(
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::at))), "[]");
m->add(
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::operator[]))), "at");
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(static_cast<indexoper>(&ContainerType::at))), "[]");
return m;
}
@@ -203,10 +171,9 @@ namespace chaiscript
{
assignable_type<ContainerType>(type, m);
m->add(fun(&ContainerType::size), "size");
m->add(fun(&ContainerType::max_size), "max_size");
m->add(fun(&ContainerType::empty), "empty");
m->add(fun(&ContainerType::clear), "clear");
m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::size), "size");
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
return m;
}
@@ -307,7 +274,7 @@ namespace chaiscript
typedef typename ContainerType::reference (ContainerType::*backptr)();
m->add(fun(backptr(&ContainerType::back)), "back");
m->add(fun(static_cast<backptr>(&ContainerType::back)), "back");
std::string push_back_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
@@ -322,6 +289,45 @@ namespace chaiscript
return m;
}
/**
*Front insertion sequence
*http://www.sgi.com/tech/stl/FrontInsertionSequence.html
*/
template<typename ContainerType>
ModulePtr front_insertion_sequence_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
sequence_type<ContainerType>(type, m);
typedef typename ContainerType::reference (ContainerType::*frontptr)();
m->add(fun(static_cast<frontptr>(&ContainerType::front)), "front");
std::string push_front_name;
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
{
push_front_name = "push_front_ref";
} else {
push_front_name = "push_front";
}
m->add(fun(&ContainerType::push_front), push_front_name);
m->add(fun(&ContainerType::pop_front), "pop_front");
return m;
}
/**
* hopefully working List type
* http://www.sgi.com/tech/stl/List.html
*/
template<typename ListType>
ModulePtr list_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
m->add(user_type<ListType>(), type);
front_insertion_sequence_type<ListType>(type, m);
back_insertion_sequence_type<ListType>(type, m);
return m;
}
/**
* Create a vector type with associated concepts
* http://www.sgi.com/tech/stl/Vector.html
@@ -387,7 +393,7 @@ namespace chaiscript
ModulePtr unique_associative_container_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
{
associative_container_type<ContainerType>(type, m);
m->add(fun(&ContainerType::count), "count");
m->add(fun<size_t (ContainerType::*)(const typename ContainerType::key_type &) const>(&ContainerType::count), "count");
return m;
}
@@ -404,7 +410,6 @@ namespace chaiscript
reversible_container_type<ContainerType>(type, m);
associative_container_type<ContainerType>(type, m);
m->add(fun(eq_range(&ContainerType::equal_range)), "equal_range");
return m;
}
@@ -462,12 +467,12 @@ namespace chaiscript
m->add(fun(&String::push_back), push_back_name);
typedef typename String::size_type (String::*find_func)(const String &, typename String::size_type) const;
m->add(fun(find_func(&String::find)), "find");
m->add(fun(find_func(&String::rfind)), "rfind");
m->add(fun(find_func(&String::find_first_of)), "find_first_of");
m->add(fun(find_func(&String::find_last_of)), "find_last_of");
m->add(fun(find_func(&String::find_first_not_of)), "find_first_not_of");
m->add(fun(find_func(&String::find_last_not_of)), "find_last_not_of");
m->add(fun(static_cast<find_func>(&String::find)), "find");
m->add(fun(static_cast<find_func>(&String::rfind)), "rfind");
m->add(fun(static_cast<find_func>(&String::find_first_of)), "find_first_of");
m->add(fun(static_cast<find_func>(&String::find_last_of)), "find_last_of");
m->add(fun(static_cast<find_func>(&String::find_first_not_of)), "find_first_not_of");
m->add(fun(static_cast<find_func>(&String::find_last_not_of)), "find_last_not_of");
return m;
}

View File

@@ -8,6 +8,7 @@
#define __boxed_value_hpp__
#include "type_info.hpp"
#include "../chaiscript_threading.hpp"
#include <map>
#include <boost/shared_ptr.hpp>
#include <boost/any.hpp>
@@ -134,6 +135,8 @@ namespace chaiscript
template<typename T>
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
{
bool b_const = boost::is_const<T>::value;
boost::shared_ptr<Data> data(new Data(
detail::Get_Type_Info<T>::get(),
boost::any(obj),
@@ -141,14 +144,14 @@ namespace chaiscript
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
);
std::map<const void *, Data>::iterator itr
= m_ptrs.find(obj.get());
std::map<std::pair<const void *, bool>, Data>::iterator itr
= m_ptrs.find(std::make_pair(obj.get(), b_const));
if (itr != m_ptrs.end())
{
(*data) = (itr->second);
} else {
m_ptrs.insert(std::make_pair(obj.get(), *data));
m_ptrs.insert(std::make_pair(std::make_pair(obj.get(), b_const), *data));
}
return data;
@@ -163,14 +166,16 @@ namespace chaiscript
template<typename T>
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
{
bool b_const = boost::is_const<T>::value;
boost::shared_ptr<Data> data(new Data(
detail::Get_Type_Info<T>::get(),
boost::any(obj),
true)
);
std::map<const void *, Data >::iterator itr
= m_ptrs.find(obj.get_pointer());
std::map<std::pair<const void *, bool>, Data >::iterator itr
= m_ptrs.find(std::make_pair(obj.get_pointer(), b_const) );
// If the ptr is found in the cache and it is the correct type,
// return it. It may be the incorrect type when two variables share the
@@ -180,7 +185,7 @@ namespace chaiscript
// Both t and t.x share the same memory location, but do not represent
// objects of the same type.
if (itr != m_ptrs.end()
&& itr->second.m_type_info.m_bare_type_info == data->m_type_info.m_bare_type_info)
&& itr->second.m_type_info.bare_equal(data->m_type_info))
{
(*data) = (itr->second);
}
@@ -200,7 +205,7 @@ namespace chaiscript
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
m_ptrs.insert(std::make_pair(ptr->get(), *data));
m_ptrs.insert(std::make_pair(std::make_pair(ptr->get(), false), *data));
return data;
}
@@ -217,21 +222,23 @@ namespace chaiscript
* Drop objects from the cache where there is only one (ie, our)
* reference to it, so it may be destructed
*/
void cull()
void cull(bool force = false)
{
++m_cullcount;
if (m_cullcount % 10 != 0)
if (force || m_cullcount % 10 != 0)
{
return;
}
std::map<const void *, Data >::iterator itr = m_ptrs.begin();
std::map<std::pair<const void *, bool>, Data>::iterator itr = m_ptrs.begin();
while (itr != m_ptrs.end())
{
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1)
{
std::map<const void *, Data >::iterator todel = itr;
std::map<std::pair<const void *, bool>, Data >::iterator todel = itr;
++itr;
m_ptrs.erase(todel);
} else {
@@ -240,7 +247,7 @@ namespace chaiscript
}
}
std::map<const void *, Data > m_ptrs;
std::map<std::pair<const void *, bool>, Data > m_ptrs;
int m_cullcount;
};
@@ -278,10 +285,15 @@ namespace chaiscript
/**
* Return a reference to the static global Object_Cache
*/
Object_Cache &get_object_cache()
static Object_Cache &get_object_cache()
{
static Object_Cache oc;
return oc;
static chaiscript::threading::Thread_Storage<Object_Cache> oc;
return *oc;
}
static void clear_cache()
{
get_object_cache().m_ptrs.clear();
}
/**
@@ -313,7 +325,7 @@ namespace chaiscript
*/
bool is_unknown() const
{
return m_data->m_type_info.m_is_unknown;
return m_data->m_type_info.is_unknown();
}
boost::any get() const
@@ -347,14 +359,19 @@ namespace chaiscript
{
if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
if (!ob.get_type_info().is_const())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
}
};
@@ -371,14 +388,19 @@ namespace chaiscript
{
if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
if (!ob.get_type_info().is_const())
{
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
} else {
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
}
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
if (!ob.get_type_info().is_const())
{
return boost::cref(*(boost::any_cast<boost::shared_ptr<Result> >(ob.get())));
} else {
return boost::cref(*(boost::any_cast<boost::shared_ptr<const Result> >(ob.get())));
}
}
}
};
@@ -395,14 +417,19 @@ namespace chaiscript
{
if (ob.is_ref())
{
if (!ob.get_type_info().m_is_const)
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
} else {
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
}
} else {
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
if (!ob.get_type_info().is_const())
{
return (boost::any_cast<boost::shared_ptr<Result> >(ob.get())).get();
} else {
return (boost::any_cast<boost::shared_ptr<const Result> >(ob.get())).get();
}
}
}
};
@@ -460,7 +487,26 @@ namespace chaiscript
};
/**
* Cast_Helper for casting to a boost::shared_ptr<> type
* Cast_Helper for casting to a boost::shared_ptr<const> type
*/
template<typename Result>
struct Cast_Helper<typename boost::shared_ptr<const Result> >
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
* Cast_Helper for casting to a const boost::shared_ptr<> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<Result> &>
@@ -473,6 +519,25 @@ namespace chaiscript
}
};
/**
* Cast_Helper for casting to a const boost::shared_ptr<const> & type
*/
template<typename Result>
struct Cast_Helper<const boost::shared_ptr<const Result> &>
{
typedef typename boost::shared_ptr<const Result> Result_Type;
static Result_Type cast(const Boxed_Value &ob)
{
if (!ob.get_type_info().is_const())
{
return boost::const_pointer_cast<const Result>(boost::any_cast<boost::shared_ptr<Result> >(ob.get()));
} else {
return boost::any_cast<boost::shared_ptr<const Result> >(ob.get());
}
}
};
/**
@@ -512,7 +577,7 @@ namespace chaiscript
{
public:
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
: from(t_from.m_type_info), to(&t_to), m_what("Cannot perform boxed_cast")
: from(t_from), to(&t_to), m_what("Cannot perform boxed_cast")
{
}
@@ -527,7 +592,8 @@ namespace chaiscript
{
return m_what.c_str();
}
const std::type_info *from;
Type_Info from;
const std::type_info *to;
private:
@@ -558,12 +624,12 @@ namespace chaiscript
Boxed_POD_Value(const Boxed_Value &v)
: d(0), i(0), m_isfloat(false)
{
if (!v.get_type_info().m_type_info)
if (v.get_type_info().is_unknown())
{
throw boost::bad_any_cast();
}
const std::type_info &inp_ = *v.get_type_info().m_type_info;
const Type_Info &inp_ = v.get_type_info();
if (inp_ == typeid(double))
{
@@ -702,6 +768,30 @@ namespace chaiscript
return Boxed_Value(t);
}
template<typename T>
Boxed_Value const_var(T *t)
{
return Boxed_Value( const_cast<typename boost::add_const<T>::type>(t) );
}
template<typename T>
Boxed_Value const_var(const boost::shared_ptr<T> &t)
{
return Boxed_Value( boost::const_pointer_cast<typename boost::add_const<T>::type>(t) );
}
template<typename T>
Boxed_Value const_var(const boost::reference_wrapper<T> &t)
{
return Boxed_Value( boost::cref(t.get()) );
}
template<typename T>
Boxed_Value const_var(const T &t)
{
return Boxed_Value(boost::shared_ptr<typename boost::add_const<T>::type >(new T(t)));
}
/**
* Return true if the two Boxed_Values share the same internal type
*/

View File

@@ -13,6 +13,7 @@
#include <set>
#include <boost/shared_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tuple/tuple.hpp>
#include <stdexcept>
#include <vector>
#include <iostream>
@@ -22,6 +23,8 @@
#include "type_info.hpp"
#include "proxy_functions.hpp"
#include "proxy_constructors.hpp"
#include "dynamic_object.hpp"
#include "../chaiscript_threading.hpp"
namespace chaiscript
{
@@ -40,16 +43,26 @@ namespace chaiscript
return *this;
}
template<typename T>
void apply(T &t) const
//Add a bit of chaiscript to eval during module implementation
Module &eval(const std::string &str)
{
m_evals.push_back(str);
return *this;
}
template<typename Eval, typename Engine>
void apply(Eval &t_eval, Engine &t_engine) const
{
apply(m_typeinfos.begin(), m_typeinfos.end(), t);
apply(m_funcs.begin(), m_funcs.end(), t);
apply(m_typeinfos.begin(), m_typeinfos.end(), t_engine);
apply(m_funcs.begin(), m_funcs.end(), t_engine);
apply_eval(m_evals.begin(), m_evals.end(), t_eval);
}
private:
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
std::vector<std::string> m_evals;
template<typename T, typename InItr>
void apply(InItr begin, InItr end, T &t) const
@@ -60,6 +73,18 @@ namespace chaiscript
++begin;
}
}
template<typename T, typename InItr>
void apply_eval(InItr begin, InItr end, T &t) const
{
while (begin != end)
{
t.eval(*begin);
++begin;
}
}
};
typedef boost::shared_ptr<Module> ModulePtr;
@@ -73,7 +98,8 @@ namespace chaiscript
{
public:
Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
: m_funcs(t_funcs)
: Proxy_Function_Base(std::vector<Type_Info>()),
m_funcs(t_funcs)
{
}
@@ -84,14 +110,9 @@ namespace chaiscript
virtual ~Dispatch_Function() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
return dispatch(m_funcs, params);
}
virtual std::vector<Type_Info> get_param_types() const
{
return std::vector<Type_Info>();
return dispatch(m_funcs.begin(), m_funcs.end(), params);
}
virtual int get_arity() const
@@ -129,6 +150,23 @@ namespace chaiscript
};
/**
* Exception thrown in the case that a multi method dispatch fails
* because no matching function was found
* at runtime due to either an arity_error, a guard_error or a bad_boxed_cast
* exception
*/
struct reserved_word_error : std::runtime_error
{
reserved_word_error(const std::string &word) throw()
: std::runtime_error("Reserved word not allowed in object name: " + word)
{
}
virtual ~reserved_word_error() throw() {}
};
/**
* Main class for the dispatchkit. Handles management
* of the object stack, functions and registered types.
@@ -138,13 +176,19 @@ namespace chaiscript
public:
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
typedef std::map<std::string, Boxed_Value> Scope;
typedef boost::shared_ptr<std::deque<Scope> > Stack;
typedef boost::tuples::tuple<std::map<std::string, Boxed_Value>, std::deque<Scope>, bool> StackData;
typedef boost::shared_ptr<StackData> Stack;
Dispatch_Engine()
: m_scopes(new Stack::element_type()),
m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
: m_place_holder(boost::shared_ptr<Placeholder_Object>(new Placeholder_Object()))
{
m_scopes->push_back(Scope());
StackData &stack = get_stack_data();
stack.get<1>().push_back(Scope());
}
~Dispatch_Engine()
{
Boxed_Value::clear_cache();
}
/**
@@ -152,15 +196,11 @@ namespace chaiscript
*/
bool add(const Proxy_Function &f, const std::string &name)
{
return add_function(f, name);
}
validate_object_name(name);
/**
* Add a module's worth of registrations to the system
*/
void add(const ModulePtr &m)
{
m->apply(*this);
StackData &stack = get_stack_data();
stack.get<0>().erase(name);
return add_function(f, name);
}
/**
@@ -169,12 +209,16 @@ namespace chaiscript
*/
void add(const Boxed_Value &obj, const std::string &name)
{
for (int i = m_scopes->size()-1; i >= 0; --i)
validate_object_name(name);
StackData &stack = get_stack_data();
for (int i = stack.get<1>().size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
std::map<std::string, Boxed_Value>::const_iterator itr = (stack.get<1>())[i].find(name);
if (itr != (stack.get<1>())[i].end())
{
(*m_scopes)[i][name] = Boxed_Value(obj);
stack.get<0>().erase(name);
(stack.get<1>())[i][name] = obj;
return;
}
}
@@ -187,7 +231,26 @@ namespace chaiscript
*/
void add_object(const std::string &name, const Boxed_Value &obj)
{
m_scopes->back()[name] = Boxed_Value(obj);
StackData &stack = get_stack_data();
validate_object_name(name);
stack.get<0>().erase(name);
stack.get<1>().back()[name] = obj;
}
/**
* Adds a new shared object, between all the threads
*/
void add_shared_object(const Boxed_Value &obj, const std::string &name)
{
StackData &stack = get_stack_data();
validate_object_name(name);
stack.get<0>().erase(name);
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_shared_object_mutex);
#endif
m_shared_objects[name] = obj;
}
/**
@@ -195,7 +258,8 @@ namespace chaiscript
*/
void new_scope()
{
m_scopes->push_back(Scope());
StackData &stack = get_stack_data();
stack.get<1>().push_back(Scope());
}
/**
@@ -203,22 +267,22 @@ namespace chaiscript
*/
void pop_scope()
{
if (m_scopes->size() > 1)
StackData &stack = get_stack_data();
if (stack.get<1>().size() > 1)
{
m_scopes->pop_back();
Scope &scope(stack.get<1>().back());
for (Scope::const_iterator itr = scope.begin();
itr != scope.end();
++itr)
{
stack.get<0>().erase(itr->first);
}
stack.get<1>().pop_back();
} else {
throw std::range_error("Unable to pop global stack");
}
}
/**
* Returns the current stack
*/
Stack get_stack()
{
return m_scopes;
}
/**
* Swaps out the stack with a new stack
* \returns the old stack
@@ -226,14 +290,33 @@ namespace chaiscript
*/
Stack set_stack(const Stack &s)
{
Stack old = m_scopes;
m_scopes = s;
Stack old = m_stack_holder->stack;
m_stack_holder->stack = s;
return old;
}
Stack new_stack()
Stack new_stack() const
{
return Stack(new Stack::element_type());
Stack s(new Stack::element_type());
s->get<1>().push_back(Scope());
s->get<2>() = false;
return s;
}
Stack get_stack() const
{
return m_stack_holder->stack;
}
void sync_cache()
{
m_stack_holder->stack->get<0>().clear();
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
get_function_cache() = m_functions;
}
/**
@@ -243,27 +326,58 @@ namespace chaiscript
*/
Boxed_Value get_object(const std::string &name) const
{
// Is it a placeholder object?
if (name == "_")
{
return m_place_holder;
}
for (int i = m_scopes->size()-1; i >= 0; --i)
StackData &stack = get_stack_data();
std::map<std::string, Boxed_Value> &cache = stack.get<0>();
// Is it in the cache?
std::map<std::string, Boxed_Value>::const_iterator itr = cache.find(name);
if (itr != cache.end())
{
std::map<std::string, Boxed_Value>::const_iterator itr = (*m_scopes)[i].find(name);
if (itr != (*m_scopes)[i].end())
return itr->second;
}
// Is it in the stack?
for (int i = stack.get<1>().size()-1; i >= 0; --i)
{
std::map<std::string, Boxed_Value>::const_iterator stackitr = (stack.get<1>())[i].find(name);
if (stackitr != (stack.get<1>())[i].end())
{
cache[name] = stackitr->second;
return stackitr->second;
}
}
// Are we in the 0th stack and should check the shared objects?
if (stack.get<2>())
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_shared_object_mutex);
#endif
itr = m_shared_objects.find(name);
if (itr != m_shared_objects.end())
{
cache[name] = itr->second;
return itr->second;
}
}
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function_impl(name, false);
// If all that failed, then check to see if it's a function
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
if (funcs.empty())
{
throw std::range_error("Object not known: " + name);
} else {
return Boxed_Value(Proxy_Function(new Dispatch_Function(funcs)));
Boxed_Value f(Const_Proxy_Function(new Dispatch_Function(funcs)));
cache[name] = f;
return f;
}
}
@@ -272,6 +386,10 @@ namespace chaiscript
*/
void add(const Type_Info &ti, const std::string &name)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
m_types.insert(std::make_pair(name, ti));
}
@@ -280,6 +398,10 @@ namespace chaiscript
*/
Type_Info get_type(const std::string &name) const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
Type_Name_Map::const_iterator itr = m_types.find(name);
if (itr != m_types.end())
@@ -297,17 +419,21 @@ namespace chaiscript
*/
std::string get_type_name(const Type_Info &ti) const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
for (Type_Name_Map::const_iterator itr = m_types.begin();
itr != m_types.end();
++itr)
{
if (itr->second.m_bare_type_info == ti.m_bare_type_info)
if (itr->second.bare_equal(ti))
{
return itr->first;
}
}
return ti.m_bare_type_info->name();
return ti.bare_name();
}
/**
@@ -315,6 +441,10 @@ namespace chaiscript
*/
std::vector<std::pair<std::string, Type_Info> > get_types() const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
return std::vector<std::pair<std::string, Type_Info> >(m_types.begin(), m_types.end());
}
@@ -324,7 +454,19 @@ namespace chaiscript
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
get_function(const std::string &t_name) const
{
return get_function_impl(t_name, true);
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= get_function_cache().equal_range(t_name);
return std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
}
/**
* Return true if a function exists
*/
bool function_exists(const std::string &name) const
{
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
return functions.find(name) != functions.end();
}
/**
@@ -332,38 +474,161 @@ namespace chaiscript
*/
std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
{
return std::vector<std::pair<std::string, Proxy_Function > >(m_functions.begin(), m_functions.end());
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
return std::vector<std::pair<std::string, Proxy_Function > >(functions.begin(), functions.end());
}
void add_reserved_word(const std::string &name)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
m_reserved_words.insert(name);
}
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> &params) const
{
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= functions.equal_range(t_name);
return dispatch(range.first, range.second, params);
}
/**
* Dump object info to stdout
*/
void dump_object(Boxed_Value o) const
{
Type_Info ti = o.get_type_info();
std::cout << (ti.is_const()?"const ":"") << get_type_name(ti) << std::endl;
}
/**
* Dump type info to stdout
*/
void dump_type(const Type_Info &type) const
{
std::cout << (type.is_const()?"const ":"") << get_type_name(type);
}
/**
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, Proxy_Function > &f) const
{
std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation();
if (annotation.size() > 0) {
std::cout << annotation;
}
dump_type(params.front());
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
itr != params.end();
)
{
dump_type(*itr);
++itr;
if (itr != params.end())
{
std::cout << ", ";
}
}
std::cout << ") " << std::endl;
}
/**
* Dump all system info to stdout
*/
void dump_system() const
{
std::cout << "Registered Types: " << std::endl;
std::vector<std::pair<std::string, Type_Info> > types = get_types();
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
itr != types.end();
++itr)
{
std::cout << itr->first << ": ";
std::cout << itr->second.bare_name();
std::cout << std::endl;
}
std::cout << std::endl;
std::vector<std::pair<std::string, Proxy_Function > > funcs = get_functions();
std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
{
dump_function(*itr);
}
std::cout << std::endl;
}
/**
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(Boxed_Value r, const std::string &user_typename) const
{
try {
if (get_type(user_typename).bare_equal(r.get_type_info()))
{
return true;
}
} catch (const std::range_error &) {
}
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(r);
return d.get_type_name() == user_typename;
} catch (const std::bad_cast &) {
}
return false;
}
std::string type_name(Boxed_Value obj) const
{
return get_type_name(obj.get_type_info());
}
private:
/**
* Implementation detail for searching for a function by name.
* Looks for all registered global functions and optionally for an object
* in scope with the same name
* Returns the current stack
* make const/non const versions
*/
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
get_function_impl(const std::string &t_name, bool include_objects) const
StackData &get_stack_data() const
{
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs;
return *(m_stack_holder->stack);
}
if (include_objects)
std::multimap<std::string, Proxy_Function> &get_function_cache() const
{
return m_stack_holder->function_cache;
}
/**
* Throw a reserved_word exception if the name is not allowed
*/
void validate_object_name(const std::string &name) const
{
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(m_mutex);
#endif
if (m_reserved_words.find(name) != m_reserved_words.end())
{
try {
funcs.insert(funcs.end(),
std::make_pair(
t_name,
boxed_cast<std::multimap<std::string, Proxy_Function >::mapped_type>(get_object(t_name)))
);
} catch (const bad_boxed_cast &) {
} catch (const std::range_error &) {
}
throw reserved_word_error(name);
}
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_functions.equal_range(t_name);
funcs.insert(funcs.end(), range.first, range.second);
return funcs;
}
/**
@@ -373,6 +638,10 @@ namespace chaiscript
*/
bool add_function(const Proxy_Function &f, const std::string &t_name)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(m_mutex);
#endif
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
= m_functions.equal_range(t_name);
@@ -386,109 +655,41 @@ namespace chaiscript
}
m_functions.insert(std::make_pair(t_name, f));
get_function_cache().insert(std::make_pair(t_name, f));
return true;
}
Stack m_scopes;
#ifndef CHAISCRIPT_NO_THREADS
mutable boost::shared_mutex m_mutex;
mutable boost::shared_mutex m_shared_object_mutex;
#endif
struct Stack_Holder
{
Stack_Holder()
: stack(new StackData())
{
stack->get<2>() = true;
}
Stack stack;
std::multimap<std::string, Proxy_Function> function_cache;
};
chaiscript::threading::Thread_Storage<Stack_Holder> m_stack_holder;
std::multimap<std::string, Proxy_Function> m_functions;
std::map<std::string, Boxed_Value> m_shared_objects;
std::multimap<std::string, Proxy_Function > m_functions;
Type_Name_Map m_types;
Boxed_Value m_place_holder;
std::set<std::string> m_reserved_words;
};
/**
* Dump object info to stdout
*/
void dump_object(Boxed_Value o, const Dispatch_Engine &e)
{
Type_Info ti = o.get_type_info();
std::cout << (ti.m_is_const?"const ":"") << e.get_type_name(ti) << std::endl;
}
/**
* Dump type info to stdout
*/
void dump_type(const Type_Info &type, const Dispatch_Engine &e)
{
std::cout << (type.m_is_const?"const ":"") << e.get_type_name(type);
}
/**
* Dump function to stdout
*/
void dump_function(const std::pair<const std::string, Proxy_Function > &f, const Dispatch_Engine &e)
{
std::vector<Type_Info> params = f.second->get_param_types();
std::string annotation = f.second->annotation();
if (annotation.size() > 0) {
std::cout << annotation;
}
dump_type(params.front(), e);
std::cout << " " << f.first << "(";
for (std::vector<Type_Info>::const_iterator itr = params.begin() + 1;
itr != params.end();
)
{
dump_type(*itr, e);
++itr;
if (itr != params.end())
{
std::cout << ", ";
}
}
std::cout << ") " << std::endl;
}
/**
* Dump all system info to stdout
*/
void dump_system(const Dispatch_Engine &s)
{
std::cout << "Registered Types: " << std::endl;
std::vector<std::pair<std::string, Type_Info> > types = s.get_types();
for (std::vector<std::pair<std::string, Type_Info> >::const_iterator itr = types.begin();
itr != types.end();
++itr)
{
std::cout << itr->first << ": ";
std::cout << itr->second.m_bare_type_info->name();
std::cout << std::endl;
}
std::cout << std::endl;
std::vector<std::pair<std::string, Proxy_Function > > funcs = s.get_functions();
std::cout << "Functions: " << std::endl;
for (std::vector<std::pair<std::string, Proxy_Function > >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
{
dump_function(*itr, s);
}
std::cout << std::endl;
}
/**
* return true if the Boxed_Value matches the registered type by name
*/
bool is_type(const Dispatch_Engine &e, const std::string &user_typename, Boxed_Value r)
{
try {
return e.get_type(user_typename) == r.get_type_info();
} catch (const std::range_error &) {
return false;
}
}
std::string type_name(const Dispatch_Engine &e, Boxed_Value obj)
{
return e.get_type_name(obj.get_type_info());
}
}
#endif

View File

@@ -0,0 +1,226 @@
#ifndef __DYNAMIC_OBJECT_HPP__
#define __DYNAMIC_OBJECT_HPP__
#include <boost/optional.hpp>
namespace chaiscript
{
class Dynamic_Object
{
public:
Dynamic_Object(const std::string &t_type_name)
: m_type_name(t_type_name)
{
}
std::string get_type_name() const
{
return m_type_name;
}
Boxed_Value get_attr(const std::string &t_attr_name)
{
return m_attrs[t_attr_name];
}
std::map<std::string, Boxed_Value> get_attrs()
{
return m_attrs;
}
private:
std::string m_type_name;
std::map<std::string, Boxed_Value> m_attrs;
};
struct Dynamic_Object_Attribute
{
static Boxed_Value func(const std::string &t_type_name, const std::string &t_attr_name,
Dynamic_Object &t_do)
{
if (t_do.get_type_name() != t_type_name)
{
throw bad_boxed_cast("Dynamic object type mismatch");
}
return t_do.get_attr(t_attr_name);
}
};
/**
* A Proxy_Function implementation designed for calling a function
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Function : public Proxy_Function_Base
{
public:
Dynamic_Object_Function(
const std::string &t_type_name,
const Proxy_Function &t_func,
const boost::optional<Type_Info> &t_ti = boost::optional<Type_Info>())
: Proxy_Function_Base(t_func->get_param_types()),
m_type_name(t_type_name), m_func(t_func), m_ti(t_ti)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
virtual ~Dynamic_Object_Function() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
try
{
const Dynamic_Object_Function &df = dynamic_cast<const Dynamic_Object_Function &>(f);
return df.m_type_name == m_type_name && (*df.m_func) == (*m_func);
} catch (const std::bad_cast &) {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
if (dynamic_object_typename_match(vals, m_type_name, m_ti))
{
return m_func->call_match(vals);
} else {
return false;
}
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
if (dynamic_object_typename_match(params, m_type_name, m_ti))
{
return (*m_func)(params);
} else {
throw guard_error();
}
}
virtual int get_arity() const
{
return m_func->get_arity();
}
virtual std::string annotation() const
{
return m_func->annotation();
}
private:
static bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
const boost::optional<Type_Info> &ti)
{
if (bvs.size() > 0)
{
try {
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bvs[0]);
return name == "Dynamic_Object" || d.get_type_name() == name;
} catch (const std::bad_cast &) {
if (ti)
{
return bvs[0].get_type_info().bare_equal(*ti);
} else {
return false;
}
}
} else {
return false;
}
}
std::string m_type_name;
Proxy_Function m_func;
boost::optional<Type_Info> m_ti;
};
/**
* A Proxy_Function implementation designed for creating a new
* Dynamic_Object
* that is automatically guarded based on the first param based on the
* param's type name
*/
class Dynamic_Object_Constructor : public Proxy_Function_Base
{
public:
Dynamic_Object_Constructor(
const std::string &t_type_name,
const Proxy_Function &t_func)
: Proxy_Function_Base(build_type_list(t_func->get_param_types())),
m_type_name(t_type_name), m_func(t_func)
{
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
}
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
{
std::vector<Type_Info>::const_iterator begin = tl.begin();
std::vector<Type_Info>::const_iterator end = tl.end();
if (begin != end)
{
++begin;
}
return std::vector<Type_Info>(begin, end);
}
virtual ~Dynamic_Object_Constructor() {}
virtual bool operator==(const Proxy_Function_Base &f) const
{
try
{
const Dynamic_Object_Constructor &dc = dynamic_cast<const Dynamic_Object_Constructor&>(f);
return dc.m_type_name == m_type_name && (*dc.m_func) == (*m_func);
} catch (const std::bad_cast &) {
return false;
}
}
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
std::vector<Boxed_Value> new_vals;
new_vals.push_back(Boxed_Value(Dynamic_Object(m_type_name)));
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
return m_func->call_match(new_vals);
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
std::vector<Boxed_Value> new_params;
chaiscript::Boxed_Value bv = var(Dynamic_Object(m_type_name));
new_params.push_back(bv);
new_params.insert(new_params.end(), params.begin(), params.end());
(*m_func)(new_params);
return bv;
}
virtual int get_arity() const
{
// "this" is not considered part of the arity
return m_func->get_arity() - 1;
}
virtual std::string annotation() const
{
return m_func->annotation();
}
private:
std::string m_type_name;
Proxy_Function m_func;
};
}
#endif

View File

@@ -30,7 +30,7 @@ namespace chaiscript
functor(const std::vector<std::pair<std::string, Proxy_Function > > &funcs)
{
FunctionType *p=0;
return build_function_caller_helper(p, funcs);
return detail::build_function_caller_helper(p, funcs);
}
/**

View File

@@ -30,7 +30,7 @@ namespace chaiscript
* value of a build_function_caller
*/
template<typename Ret>
class Function_Caller_Ret
struct Function_Caller_Ret
{
static Ret call(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs,
const std::vector<Boxed_Value> &params)

View File

@@ -23,27 +23,27 @@ namespace chaiscript
template<typename Ret>
struct Handle_Return
{
static Boxed_Value call(const boost::function<Ret ()> &f)
static Boxed_Value handle(const Ret &r)
{
return Boxed_Value(f());
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<boost::shared_ptr<Ret> & ()> &f)
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(f());
return Boxed_Value(r);
}
};
template<typename Ret>
struct Handle_Return<const boost::shared_ptr<Ret> &>
{
static Boxed_Value call(const boost::function<const boost::shared_ptr<Ret> & ()> &f)
static Boxed_Value handle(const boost::shared_ptr<Ret> &r)
{
return Boxed_Value(f());
return Boxed_Value(r);
}
};
@@ -53,9 +53,9 @@ namespace chaiscript
template<typename Ret>
struct Handle_Return<Ret &>
{
static Boxed_Value call(const boost::function<Ret &()> &f)
static Boxed_Value handle(Ret &r)
{
return Boxed_Value(boost::ref(f()));
return Boxed_Value(boost::ref(r));
}
};
@@ -65,9 +65,9 @@ namespace chaiscript
template<>
struct Handle_Return<Boxed_Value>
{
static Boxed_Value call(const boost::function<Boxed_Value ()> &f)
static Boxed_Value handle(const Boxed_Value &r)
{
return f();
return r;
}
};
@@ -77,9 +77,9 @@ namespace chaiscript
template<>
struct Handle_Return<Boxed_Value &>
{
static Boxed_Value call(const boost::function<Boxed_Value &()> &f)
static Boxed_Value handle(const Boxed_Value &r)
{
return f();
return r;
}
};
@@ -89,9 +89,8 @@ namespace chaiscript
template<>
struct Handle_Return<void>
{
static Boxed_Value call(const boost::function<void ()> &f)
static Boxed_Value handle()
{
f();
return Boxed_Value(Boxed_Value::Void_Type());
}
};

View File

@@ -13,7 +13,6 @@
#include "type_info.hpp"
#include <string>
#include <boost/function.hpp>
#include <stdexcept>
#include <vector>
#include "proxy_functions_detail.hpp"
@@ -63,8 +62,10 @@ namespace chaiscript
{
public:
virtual ~Proxy_Function_Base() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) = 0;
virtual std::vector<Type_Info> get_param_types() const = 0;
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const = 0;
std::vector<Type_Info> get_param_types() const { return m_types; }
virtual bool operator==(const Proxy_Function_Base &) const = 0;
virtual bool call_match(const std::vector<Boxed_Value> &vals) const = 0;
@@ -91,10 +92,10 @@ namespace chaiscript
const Type_Info &ti = types[1];
if (!ti.m_bare_type_info || !(vals[0].get_type_info().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_Value>().m_bare_type_info)
|| (*ti.m_bare_type_info) == (*user_type<Boxed_POD_Value>().m_bare_type_info)
|| (*vals[0].get_type_info().m_bare_type_info) == (*ti.m_bare_type_info))
if (ti.is_unknown() || vals[0].get_type_info().is_unknown()
|| ti.bare_equal(user_type<Boxed_Value>())
|| ti.bare_equal(user_type<Boxed_POD_Value>())
|| ti.bare_equal(vals[0].get_type_info()))
{
return true;
} else {
@@ -109,9 +110,36 @@ namespace chaiscript
virtual int get_arity() const = 0;
virtual std::string annotation() const = 0;
protected:
Proxy_Function_Base(const std::vector<Type_Info> &t_types)
: m_types(t_types)
{
}
bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs) const
{
if (tis.size() - 1 != bvs.size())
{
return false;
} else {
const int size = bvs.size();
for (int i = 0; i < size; ++i)
{
if (!(tis[i+1].bare_equal(bvs[i].get_type_info()) && tis[i+1].is_const() >= bvs[i].get_type_info().is_const() ))
{
return false;
}
}
}
return true;
}
std::vector<Type_Info> m_types;
};
typedef boost::shared_ptr<Proxy_Function_Base> Proxy_Function;
typedef boost::shared_ptr<const Proxy_Function_Base> Const_Proxy_Function;
/**
* Exception thrown if a function's guard fails to execute
@@ -139,8 +167,8 @@ namespace chaiscript
int t_arity=-1,
const std::string &t_description = "",
const Proxy_Function &t_guard = Proxy_Function())
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard),
m_types(build_param_type_list(t_arity))
: Proxy_Function_Base(build_param_type_list(t_arity)),
m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard)
{
}
@@ -157,7 +185,7 @@ namespace chaiscript
virtual ~Dynamic_Proxy_Function() {}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
if (m_arity < 0 || params.size() == size_t(m_arity))
{
@@ -179,11 +207,6 @@ namespace chaiscript
return m_arity;
}
virtual std::vector<Type_Info> get_param_types() const
{
return m_types;
}
virtual std::string annotation() const
{
return m_description;
@@ -229,7 +252,6 @@ namespace chaiscript
int m_arity;
std::string m_description;
Proxy_Function m_guard;
std::vector<Type_Info> m_types;
};
/**
@@ -249,9 +271,10 @@ namespace chaiscript
class Bound_Function : public Proxy_Function_Base
{
public:
Bound_Function(const Proxy_Function &t_f,
Bound_Function(const Const_Proxy_Function &t_f,
const std::vector<Boxed_Value> &t_args)
: m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
: Proxy_Function_Base(std::vector<Type_Info>()),
m_f(t_f), m_args(t_args), m_arity(m_f->get_arity()<0?-1:(m_f->get_arity() - m_args.size()))
{
}
@@ -267,7 +290,7 @@ namespace chaiscript
return m_f->call_match(build_param_list(vals));
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
return (*m_f)(build_param_list(params));
}
@@ -310,11 +333,6 @@ namespace chaiscript
return args;
}
virtual std::vector<Type_Info> get_param_types() const
{
return std::vector<Type_Info>();
}
virtual int get_arity() const
{
return m_arity;
@@ -326,7 +344,7 @@ namespace chaiscript
}
private:
Proxy_Function m_f;
Const_Proxy_Function m_f;
std::vector<Boxed_Value> m_args;
int m_arity;
};
@@ -341,7 +359,8 @@ namespace chaiscript
{
public:
Proxy_Function_Impl(const boost::function<Func> &f)
: m_f(f), m_dummy_func(0), m_types(build_param_type_list(m_dummy_func))
: Proxy_Function_Base(build_param_type_list(static_cast<Func *>(0))),
m_f(f), m_dummy_func(0)
{
}
@@ -357,14 +376,9 @@ namespace chaiscript
}
}
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params)
virtual Boxed_Value operator()(const std::vector<Boxed_Value> &params) const
{
return call_func(m_f, params);
}
virtual std::vector<Type_Info> get_param_types() const
{
return m_types;
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
}
virtual int get_arity() const
@@ -375,7 +389,12 @@ namespace chaiscript
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
{
return compare_types(m_dummy_func, vals);
if (int(vals.size()) != get_arity())
{
return false;
}
return compare_types(m_types, vals) || compare_types_cast(m_dummy_func, vals);
}
virtual std::string annotation() const
@@ -386,7 +405,6 @@ namespace chaiscript
private:
boost::function<Func> m_f;
Func *m_dummy_func;
std::vector<Type_Info> m_types;
};
/**
@@ -410,17 +428,16 @@ namespace chaiscript
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
Boxed_Value dispatch(const std::vector<std::pair<std::string, Proxy_Function> > &funcs,
template<typename InItr>
Boxed_Value dispatch(InItr begin, InItr end,
const std::vector<Boxed_Value> &plist)
{
for (std::vector<std::pair<std::string, Proxy_Function> >::const_iterator itr = funcs.begin();
itr != funcs.end();
++itr)
while (begin != end)
{
try {
if (itr->second->filter(plist))
if (begin->second->filter(plist))
{
return (*itr->second)(plist);
return (*begin->second)(plist);
}
} catch (const bad_boxed_cast &) {
//parameter failed to cast, try again
@@ -430,9 +447,23 @@ namespace chaiscript
//guard failed to allow the function to execute,
//try again
}
++begin;
}
throw dispatch_error();
}
/**
* Take a vector of functions and a vector of parameters. Attempt to execute
* each function against the set of parameters, in order, until a matching
* function is found or throw dispatch_error if no matching function is found
*/
template<typename Funcs>
Boxed_Value dispatch(const Funcs &funcs,
const std::vector<Boxed_Value> &plist)
{
return dispatch(funcs.begin(), funcs.end(), plist);
}
}

View File

@@ -7,11 +7,9 @@
#include <boost/preprocessor.hpp>
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
#define casthelper(z,n,text) ,chaiscript::boxed_cast< Param ## n >(params[n])
#define comparetype(z,n,text) && ((detail::Get_Type_Info<Param ## n>::get() == params[n].get_type_info()))
#define casthelper(z,n,text) BOOST_PP_COMMA_IF(n) chaiscript::boxed_cast< Param ## n >(params[n])
#define trycast(z,n,text) chaiscript::boxed_cast<Param ## n>(params[n]);
#ifndef BOOST_PP_IS_ITERATING
#ifndef __proxy_functions_detail_hpp__
#define __proxy_functions_detail_hpp__
@@ -45,6 +43,27 @@ namespace chaiscript
int got;
int expected;
};
template<typename Ret>
struct Do_Call
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
return Handle_Return<Ret>::handle(call_func(fun, params));
}
};
template<>
struct Do_Call<void>
{
template<typename Fun>
static Boxed_Value go(const boost::function<Fun> &fun, const std::vector<Boxed_Value> &params)
{
call_func(fun, params);
return Handle_Return<void>::handle();
};
};
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
@@ -80,14 +99,14 @@ namespace chaiscript
* the bad_boxed_cast is passed up to the caller.
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Boxed_Value call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
Ret call_func(const boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))> &f,
const std::vector<Boxed_Value> &params)
{
if (params.size() != n)
{
throw arity_error(params.size(), n);
} else {
return Handle_Return<Ret>::call(boost::bind(f BOOST_PP_REPEAT(n, casthelper, ~)));
return f(BOOST_PP_REPEAT(n, casthelper, ~));
}
}
@@ -97,25 +116,18 @@ namespace chaiscript
* registration of two functions with the exact same signatures
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
bool compare_types(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> &params)
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
const std::vector<Boxed_Value> & BOOST_PP_IF(n, params, ))
{
if (params.size() != n)
{
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
} else {
bool val = true BOOST_PP_REPEAT(n, comparetype, ~);
if (val) return true;
try {
BOOST_PP_REPEAT(n, trycast, ~);
} catch (const bad_boxed_cast &) {
return false;
}
return true;
}
return true;
}
}
#endif

View File

@@ -4,24 +4,18 @@
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <boost/preprocessor.hpp>
#ifndef BOOST_PP_IS_ITERATING
#ifndef __register_function_hpp__
#define __register_function_hpp__
#include "dispatchkit.hpp"
#include "bind_first.hpp"
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/function_types/components.hpp>
#include <boost/function_types/function_type.hpp>
namespace chaiscript
{
template<typename T>
Proxy_Function fun(const boost::function<T> &f)
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
namespace detail
{
/**
@@ -32,58 +26,65 @@ namespace chaiscript
{
return (obj->*m);
}
template<typename T>
boost::function<T> mk_boost_fun(const boost::function<T> &f)
{
return f;
}
template<typename T>
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
> mk_boost_fun(T t)
{
return
boost::function<
typename boost::function_types::function_type<boost::function_types::components<T> >::type
>(t);
}
template<typename T, typename Class>
Proxy_Function fun_helper(T Class::* m)
{
return fun_helper(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
}
template<typename T>
Proxy_Function fun_helper(const boost::function<T> &f)
{
return Proxy_Function(new Proxy_Function_Impl<T>(f));
}
}
/**
* Automatically create a get_member helper function for an object
* to allow for runtime dispatched access to public data members
* for example, the case of std::pair<>::first and std::pair<>::second
*/
template<typename T, typename Class>
Proxy_Function fun(T Class::* m)
template<typename T>
Proxy_Function fun(const boost::function<T> &f)
{
return fun(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
return detail::fun_helper(f);
}
template<typename T>
Proxy_Function fun(T t)
{
return detail::fun_helper(detail::mk_boost_fun(t));
}
template<typename T, typename Q>
Proxy_Function fun(T t, const Q &q)
{
return detail::fun_helper(bind_first(t, q));
}
template<typename T, typename Q, typename R>
Proxy_Function fun(T t, const Q &q, const R &r)
{
return detail::fun_helper(bind_first(bind_first(t, q), r));
}
}
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp>
#include BOOST_PP_ITERATE()
# endif
#else
# define n BOOST_PP_ITERATION()
namespace chaiscript
{
/**
* Register a global function of n parameters with name
*/
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Proxy_Function fun(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
return fun(boost::function<Ret (BOOST_PP_ENUM_PARAMS(n, Param))>(f));
}
/**
* Register a class method of n parameters with name
*/
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Proxy_Function fun(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
{
return fun(boost::function<Ret (Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
}
/**
* Register a const class method of n parameters with name
*/
template<typename Ret, typename Class BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
Proxy_Function fun(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const)
{
return fun(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
}
}
#endif

View File

@@ -21,60 +21,91 @@ namespace chaiscript
/**
* compile time deduced information about a type
*/
struct Type_Info
class Type_Info
{
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
const std::type_info *t_ti, const std::type_info *t_bareti)
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
public:
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
const std::type_info *t_ti, const std::type_info *t_bareti)
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
m_is_void(t_is_void),
m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_unknown(false)
{
}
m_type_info(t_ti), m_bare_type_info(t_bareti),
m_is_unknown(false)
{
}
Type_Info()
: m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_type_info(0), m_bare_type_info(0),
m_is_unknown(true)
{
}
Type_Info()
: m_is_const(false), m_is_reference(false), m_is_pointer(false),
m_is_void(false), m_type_info(0), m_bare_type_info(0),
m_is_unknown(true)
{
}
Type_Info(const Type_Info &ti)
: m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_unknown(ti.m_is_unknown)
{
}
Type_Info &operator=(const Type_Info &ti)
{
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_unknown = ti.m_is_unknown;
return *this;
}
bool operator<(const Type_Info &ti) const
{
return m_type_info < ti.m_type_info;
}
Type_Info(const Type_Info &ti)
: m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
m_is_pointer(ti.m_is_pointer),
m_is_void(ti.m_is_void), m_type_info(ti.m_type_info),
m_bare_type_info(ti.m_bare_type_info),
m_is_unknown(ti.m_is_unknown)
{
}
bool operator==(const Type_Info &ti) const
{
return ti.m_type_info == m_type_info;
}
Type_Info &operator=(const Type_Info &ti)
{
m_is_const = ti.m_is_const;
m_is_reference = ti.m_is_reference;
m_is_pointer = ti.m_is_pointer;
m_is_void = ti.m_is_void;
m_type_info = ti.m_type_info;
m_bare_type_info = ti.m_bare_type_info;
m_is_unknown = ti.m_is_unknown;
return *this;
}
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_unknown;
bool operator<(const Type_Info &ti) const
{
return m_type_info < ti.m_type_info;
}
bool operator==(const Type_Info &ti) const
{
return ti.m_type_info == m_type_info
|| (ti.m_type_info && m_type_info && *ti.m_type_info == *m_type_info);
}
bool operator==(const std::type_info &ti) const
{
return m_type_info != 0 && (*m_type_info) == ti;
}
bool bare_equal(const Type_Info &ti) const
{
return ti.m_bare_type_info == m_bare_type_info
|| (ti.m_bare_type_info && m_bare_type_info && *ti.m_bare_type_info == *m_bare_type_info);
}
bool is_const() const { return m_is_const; }
bool is_reference() const { return m_is_reference; }
bool is_void() const { return m_is_void; }
bool is_unknown() const { return m_is_unknown || m_bare_type_info == 0; }
std::string bare_name() const
{
if (m_bare_type_info)
{
return m_bare_type_info->name();
} else {
return "";
}
}
private:
bool m_is_const;
bool m_is_reference;
bool m_is_pointer;
bool m_is_void;
const std::type_info *m_type_info;
const std::type_info *m_bare_type_info;
bool m_is_unknown;
};
namespace detail
@@ -106,6 +137,18 @@ namespace chaiscript
}
};
template<typename T>
struct Get_Type_Info<const boost::shared_ptr<T> &>
{
static Type_Info get()
{
return Type_Info(boost::is_const<T>::value, boost::is_reference<T>::value, boost::is_pointer<T>::value,
boost::is_void<T>::value,
&typeid(const boost::shared_ptr<T> &),
&typeid(typename boost::remove_const<typename boost::remove_pointer<typename boost::remove_reference<T>::type>::type>::type));
}
};
template<typename T>
struct Get_Type_Info<boost::reference_wrapper<T> >
{
@@ -132,7 +175,6 @@ namespace chaiscript
return detail::Get_Type_Info<T>::get();
}
}
#endif

View File

@@ -0,0 +1,135 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#ifndef _CHAISCRIPT_COMMON_HPP
#define _CHAISCRIPT_COMMON_HPP
#ifdef BOOST_HAS_DECLSPEC
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
#else
#define CHAISCRIPT_MODULE_EXPORT extern "C"
#endif
namespace chaiscript
{
typedef ModulePtr (*Create_Module_Func)();
/**
* 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, Inplace_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, Try, Catch, Finally, Method, Attr_Decl, Shift }; };
namespace
{
/**
* 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", "Inplace_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", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift"};
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;
bool is_cached;
Boxed_Value cached_value;
std::vector<TokenPtr> children;
TokenPtr annotation;
Token(const std::string &token_text, int id, const char *fname) :
text(token_text), identifier(id), filename(fname), is_cached(false) { }
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), is_cached(false) {
start.line = start_line;
start.column = start_col;
end.line = end_line;
end.column = end_col;
}
};
/**
* Errors generated during parsing or evaluation
*/
struct Eval_Error : public std::runtime_error {
std::string reason;
File_Position start_position;
File_Position end_position;
const char *filename;
Eval_Error(const std::string &why, const File_Position &where, const char *fname) :
std::runtime_error("Error: \"" + why + "\" " +
(std::string(fname) != "__EVAL__" ? ("in '" + std::string(fname) + "' ") : "during evaluation ") +
+ "at (" + boost::lexical_cast<std::string>(where.line) + ", " +
boost::lexical_cast<std::string>(where.column) + ")"),
reason(why), start_position(where), end_position(where), filename(fname)
{ }
Eval_Error(const std::string &why, const TokenPtr &where)
: std::runtime_error("Error: \"" + why + "\" " +
(std::string(where->filename) != "__EVAL__" ? ("in '" + std::string(where->filename) + "' ") : "during evaluation ") +
"at (" + boost::lexical_cast<std::string>(where->start.line) + ", " +
boost::lexical_cast<std::string>(where->start.column) + ")"),
reason(why), start_position(where->start), end_position(where->end), filename(where->filename) {
}
virtual ~Eval_Error() throw() {}
};
/**
* Special type for returned values
*/
struct Return_Value {
Boxed_Value retval;
TokenPtr location;
Return_Value(const 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) { }
};
}
#endif /* _CHAISCRIPT_COMMON_HPP */

View File

@@ -10,33 +10,288 @@
#include <exception>
#include <fstream>
#include <chaiscript/language/chaiscript_common.hpp>
#include "chaiscript_prelude.hpp"
#include "chaiscript_parser.hpp"
#ifdef _POSIX_VERSION
#include <dlfcn.h>
#else
#ifdef WIN32
#include <Windows.h>
#endif
#endif
#include <chaiscript/language/chaiscript_prelude.hpp>
#include <chaiscript/language/chaiscript_parser.hpp>
namespace chaiscript
{
struct load_module_error : std::runtime_error
{
load_module_error(const std::string &reason) throw()
: std::runtime_error(reason)
{
}
virtual ~load_module_error() throw()
{
}
};
#ifdef _POSIX_VERSION
struct Loadable_Module
{
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(dlopen(t_filename.c_str(), RTLD_NOW))
{
if (!m_data)
{
throw load_module_error(dlerror());
}
}
DLModule(const DLModule &); // Explicitly unimplemented copy constructor
DLModule &operator=(const DLModule &); // Explicitly unimplemented assignment operator
~DLModule()
{
dlclose(m_data);
}
void *m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(dlsym(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw load_module_error(dlerror());
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
{
}
ModulePtr get()
{
return m_func.m_symbol();
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
};
#else
#ifdef WIN32
struct Loadable_Module
{
template<typename T>
static std::wstring towstring(const T &str)
{
return std::wstring(str.begin(), str.end());
}
template<typename T>
static std::string tostring(const T &str)
{
return std::string(str.begin(), str.end());
}
#ifdef _UNICODE
template<typename T>
static std::wstring toproperstring(const T &str)
{
return towstring(str);
}
#else
template<typename T>
static std::string toproperstring(const T &str)
{
return tostring(str);
}
#endif
static std::string GetErrorMessage(DWORD err)
{
#ifdef _UNICODE
typedef LPWSTR StringType;
std::wstring retval = L"Unknown Error";
#else
typedef LPSTR StringType;
std::string retval = "Unknown Error";
#endif
StringType lpMsgBuf = 0;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(StringType)&lpMsgBuf,
0, NULL );
if (lpMsgBuf)
{
retval = lpMsgBuf;
}
LocalFree(lpMsgBuf);
return tostring(retval);
}
struct DLModule
{
DLModule(const std::string &t_filename)
: m_data(LoadLibrary(toproperstring(t_filename).c_str()))
{
if (!m_data)
{
throw load_module_error(GetErrorMessage(GetLastError()));
}
}
~DLModule()
{
FreeLibrary(m_data);
}
HMODULE m_data;
};
template<typename T>
struct DLSym
{
DLSym(DLModule &t_mod, const std::string &t_symbol)
: m_symbol(reinterpret_cast<T>(GetProcAddress(t_mod.m_data, t_symbol.c_str())))
{
if (!m_symbol)
{
throw load_module_error(GetErrorMessage(GetLastError()));
}
}
T m_symbol;
};
Loadable_Module(const std::string &t_module_name, const std::string &t_filename)
: m_dlmodule(t_filename), m_func(m_dlmodule, "create_chaiscript_module_" + t_module_name)
{
}
ModulePtr get()
{
return m_func.m_symbol();
}
DLModule m_dlmodule;
DLSym<Create_Module_Func> m_func;
};
#else
struct Loadable_Module
{
Loadable_Module(const std::string &, const std::string &)
{
throw load_module_error("Loadable module support not available for your platform");
}
ModulePtr get()
{
throw load_module_error("Loadable module support not available for your platform");
}
};
#endif
#endif
typedef boost::shared_ptr<Loadable_Module> Loadable_Module_Ptr;
template <typename Eval_Engine>
class ChaiScript_System {
#ifndef CHAISCRIPT_NO_THREADS
mutable boost::shared_mutex mutex;
mutable boost::recursive_mutex use_mutex;
#endif
std::set<std::string> loaded_files;
std::map<std::string, Loadable_Module_Ptr> loaded_modules;
Eval_Engine engine;
ChaiScript_Parser parser;
/**
* Evaluates the given string in by parsing it and running the results through the evaluator
*/
Boxed_Value do_eval(const std::string &input, const char *filename = "__EVAL__") {
Boxed_Value do_eval(const std::string &input, const std::string &filename = "__EVAL__", bool internal = false) {
ChaiScript_Parser parser;
if (!internal)
{
engine.sync_cache();
}
//debug_print(tokens);
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());
// Keep a cache of all loaded filenames and use the char * from this cache to pass
// to the parser. This is so that the parser does not have the overhead of passing
// around and copying strings
//
if (filename != "__EVAL__")
{
#ifndef CHAISCRIPT_NO_THREADS
boost::unique_lock<boost::shared_mutex> l(mutex);
#endif
loaded_files.insert(filename);
try {
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
#ifndef CHAISCRIPT_NO_THREADS
l.unlock();
#endif
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
} else {
try {
#ifndef CHAISCRIPT_NO_THREADS
boost::shared_lock<boost::shared_mutex> l(mutex);
#endif
const char *fname = loaded_files.find("__EVAL__")->c_str();
#ifndef CHAISCRIPT_NO_THREADS
l.unlock();
#endif
if (parser.parse(input, fname)) {
//parser.show_match_stack();
value = eval_token<Eval_Engine>(engine, parser.ast());
}
}
catch (const Return_Value &rv) {
value = rv.retval;
}
}
catch (const Return_Value &rv) {
value = rv.retval;
if (!internal)
{
engine.sync_cache();
}
return value;
@@ -45,16 +300,45 @@ namespace chaiscript
/**
* Evaluates the given boxed string, used during eval() inside of a script
*/
const Boxed_Value internal_eval(const std::vector<Boxed_Value> &vals) {
return do_eval(boxed_cast<std::string>(vals.at(0)));
const Boxed_Value internal_eval(const std::string &e) {
return do_eval(e, "__EVAL__", true);
}
void use(const std::string &filename)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
boost::shared_lock<boost::shared_mutex> l2(mutex);
#endif
if (loaded_files.count(filename) == 0)
{
#ifndef CHAISCRIPT_NO_THREADS
l2.unlock();
#endif
eval_file(filename);
} else {
engine.sync_cache();
}
}
public:
ChaiScript_System() {
loaded_files.insert("__EVAL__"); // Make sure the default name is already registered
build_eval_system();
}
/**
* Adds a shared object, that can be used by all threads, to the system
*/
ChaiScript_System &add_shared_object(const Boxed_Value &bv, const std::string &name)
{
engine.add_shared_object(bv, name);
return *this;
}
/**
* Adds an object to the system: type, function, object
*/
@@ -70,11 +354,61 @@ namespace chaiscript
*/
ChaiScript_System &add(const ModulePtr &p)
{
engine.add(p);
p->apply(*this, this->get_eval_engine());
return *this;
}
/**
* Load a dynamic library containing a chaiscript module
*/
void load_module(const std::string &t_module_name)
{
std::vector<std::string> prefixes;
prefixes.push_back("lib");
prefixes.push_back("");
std::vector<std::string> postfixes;
postfixes.push_back(".dll");
postfixes.push_back(".so");
postfixes.push_back("");
for (size_t i = 0; i < prefixes.size(); ++i)
{
for (size_t j = 0; j < postfixes.size(); ++j)
{
try {
std::string name = prefixes[i] + t_module_name + postfixes[j];
load_module(t_module_name, name);
return;
} catch (const load_module_error &) {
// Try next set
}
}
}
throw load_module_error("Unable to find module: " + t_module_name);
}
/**
* Load a dynamic library and provide the file name to load it from
*/
void load_module(const std::string &t_module_name, const std::string &t_filename)
{
#ifndef CHAISCRIPT_NO_THREADS
boost::lock_guard<boost::recursive_mutex> l(use_mutex);
#endif
if (loaded_modules.count(t_module_name) == 0)
{
Loadable_Module_Ptr lm(new Loadable_Module(t_module_name, t_filename));
loaded_modules[t_module_name] = lm;
add(lm->get());
} else {
engine.sync_cache();
}
}
/**
* Helper for calling script code as if it were native C++ code
* example:
@@ -117,12 +451,11 @@ namespace chaiscript
/**
* Helper function for loading a file
*/
std::string load_file(const char *filename) {
std::ifstream infile (filename, std::ios::in | std::ios::ate);
std::string load_file(const std::string &filename) {
std::ifstream infile (filename.c_str(), std::ios::in | std::ios::ate);
if (!infile.is_open()) {
std::string fname = filename;
throw std::runtime_error("Can not open: " + fname);
throw std::runtime_error("Can not open: " + filename);
}
std::streampos size = infile.tellg();
@@ -141,23 +474,47 @@ namespace chaiscript
*/
void build_eval_system() {
using namespace bootstrap;
engine.add(Bootstrap::bootstrap());
engine.add_reserved_word("def");
engine.add_reserved_word("fun");
engine.add_reserved_word("while");
engine.add_reserved_word("for");
engine.add_reserved_word("if");
engine.add_reserved_word("else");
engine.add_reserved_word("&&");
engine.add_reserved_word("||");
engine.add_reserved_word(",");
engine.add_reserved_word(":=");
engine.add_reserved_word("var");
engine.add_reserved_word("return");
engine.add_reserved_word("break");
engine.add_reserved_word("true");
engine.add_reserved_word("false");
engine.add_reserved_word("_");
engine.add(fun(boost::function<void ()>(boost::bind(&dump_system, boost::ref(engine)))), "dump_system");
engine.add(fun(boost::function<void (Boxed_Value)>(boost::bind(&dump_object, _1, boost::ref(engine)))), "dump_object");
engine.add(fun(boost::function<bool (Boxed_Value, const std::string &)>(boost::bind(&is_type, boost::ref(engine), _2, _1))),
"is_type");
add(Bootstrap::bootstrap());
engine.add(fun(boost::function<std::string (Boxed_Value)>(boost::bind(&chaiscript::type_name, boost::ref(engine), _1))),
"type_name");
engine.add(fun(&Eval_Engine::dump_system, boost::ref(engine)), "dump_system");
engine.add(fun(&Eval_Engine::dump_object, boost::ref(engine)), "dump_object");
engine.add(fun(&Eval_Engine::is_type, boost::ref(engine)), "is_type");
engine.add(fun(&Eval_Engine::type_name, boost::ref(engine)), "type_name");
engine.add(fun(&Eval_Engine::function_exists, boost::ref(engine)), "function_exists");
engine.add(vector_type<std::vector<Boxed_Value> >("Vector"));
engine.add(string_type<std::string>("string"));
engine.add(map_type<std::map<std::string, Boxed_Value> >("Map"));
engine.add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
engine.add(Proxy_Function(
new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::internal_eval, boost::ref(*this), _1), 1)), "eval");
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_1)(const std::string&);
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_2)(const std::string&, const std::string&);
engine.add(fun(static_cast<load_mod_1>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
engine.add(fun(static_cast<load_mod_2>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
add(vector_type<std::vector<Boxed_Value> >("Vector"));
add(string_type<std::string>("string"));
add(map_type<std::map<std::string, Boxed_Value> >("Map"));
add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
engine.add(fun(&ChaiScript_System<Eval_Engine>::use, this), "use");
engine.add(fun(&ChaiScript_System<Eval_Engine>::internal_eval, this), "eval");
do_eval(chaiscript_prelude, "standard prelude");
}
@@ -176,7 +533,7 @@ namespace chaiscript
/**
* Loads the file specified by filename, evaluates it, and returns the result
*/
Boxed_Value eval_file(const char *filename) {
Boxed_Value eval_file(const std::string &filename) {
return do_eval(load_file(filename), filename);
}
@@ -184,7 +541,7 @@ namespace chaiscript
* Loads the file specified by filename, evaluates it, and returns the as the specified type
*/
template<typename T>
T eval_file(const char *filename) {
T eval_file(const std::string &filename) {
return boxed_cast<T>(do_eval(load_file(filename), filename));
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@
#include <exception>
#include <fstream>
#include <sstream>
#include "chaiscript_prelude.hpp"
@@ -30,6 +31,9 @@ namespace chaiscript
singleline_comment = "//";
}
ChaiScript_Parser(const ChaiScript_Parser &); // explicitly unimplemented copy constructor
ChaiScript_Parser &operator=(const ChaiScript_Parser &); // explicitly unimplemented assignment operator
/**
* Prints the parsed tokens as a tree
*/
@@ -68,7 +72,7 @@ namespace chaiscript
*/
void build_match(Token_Type::Type match_type, int match_start) {
//so we want to take everything to the right of this and make them children
if (match_start != (int)match_stack.size()) {
if (match_start != int(match_stack.size())) {
TokenPtr t(new Token("", match_type, filename, match_stack[match_start]->start.line, match_stack[match_start]->start.column, line, col));
t->children.assign(match_stack.begin() + (match_start), match_stack.end());
match_stack.erase(match_stack.begin() + (match_start), match_stack.end());
@@ -140,7 +144,9 @@ namespace chaiscript
*/
bool Float_() {
bool retval = false;
if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) {
std::string::iterator start = input_pos;
if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*input_pos == '.'))) {
while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) {
++input_pos;
++col;
@@ -161,10 +167,47 @@ namespace chaiscript
}
}
}
return retval;
}
/**
* Reads a floating point value from input, without skipping initial whitespace
*/
bool Hex_() {
bool retval = false;
if ((input_pos != input_end) && (*input_pos == '0')) {
++input_pos;
++col;
if ((input_pos != input_end) && ((*input_pos == 'x') || (*input_pos == 'X'))) {
++input_pos;
++col;
if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) ||
((*input_pos >= 'a') && (*input_pos <= 'f')) ||
((*input_pos >= 'A') && (*input_pos <= 'F')))) {
retval = true;
while ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) ||
((*input_pos >= 'a') && (*input_pos <= 'f')) ||
((*input_pos >= 'A') && (*input_pos <= 'F')))) {
++input_pos;
++col;
}
}
else {
--input_pos;
--col;
}
}
else {
--input_pos;
--col;
}
}
return retval;
}
/**
* Reads a number from the input, detecting if it's an integer or floating point
*/
@@ -172,13 +215,25 @@ namespace chaiscript
SkipWS();
if (!capture) {
return Float_();
return Hex_() || Float_();
}
else {
std::string::iterator start = input_pos;
int prev_col = col;
int prev_line = line;
if ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) {
if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*input_pos == '.')) ) {
if (Hex_()) {
std::string match(start, input_pos);
std::stringstream ss(match);
int temp_int;
ss >> std::hex >> temp_int;
std::ostringstream out_int;
out_int << temp_int;
TokenPtr t(new Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
return true;
}
if (Float_()) {
std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col));
@@ -187,8 +242,20 @@ namespace chaiscript
}
else {
std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
if ((match.size() > 0) && (match[0] == '0')) {
std::stringstream ss(match);
int temp_int;
ss >> std::oct >> temp_int;
std::ostringstream out_int;
out_int << temp_int;
TokenPtr t(new Token(out_int.str(), Token_Type::Int, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
}
else {
TokenPtr t(new Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
}
return true;
}
}
@@ -211,7 +278,32 @@ namespace chaiscript
++col;
}
}
else if ((input_pos != input_end) && (*input_pos == '`')) {
retval = true;
++col;
++input_pos;
std::string::iterator start = input_pos;
while ((input_pos != input_end) && (*input_pos != '`')) {
if (Eol()) {
throw Eval_Error("Carriage return in identifier literal", File_Position(line, col), filename);
}
else {
++input_pos;
++col;
}
}
if (start == input_pos) {
throw Eval_Error("Missing contents of identifier literal", File_Position(line, col), filename);
}
else if (input_pos == input_end) {
throw Eval_Error("Incomplete identifier literal", File_Position(line, col), filename);
}
++col;
++input_pos;
}
return retval;
}
@@ -229,10 +321,19 @@ namespace chaiscript
int prev_col = col;
int prev_line = line;
if (Id_()) {
std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
return true;
if (*start == '`') {
//Id Literal
std::string match(start+1, input_pos-1);
TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
return true;
}
else {
std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
return true;
}
}
else {
return false;
@@ -323,37 +424,132 @@ namespace chaiscript
if (Quoted_String_()) {
std::string match;
bool is_escaped = false;
for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) {
if (*s == '\\') {
if (is_escaped) {
match.push_back('\\');
is_escaped = false;
}
else {
is_escaped = true;
}
}
else {
if (is_escaped) {
switch (*s) {
case ('b') : match.push_back('\b'); break;
case ('f') : match.push_back('\f'); break;
case ('n') : match.push_back('\n'); break;
case ('r') : match.push_back('\r'); break;
case ('t') : match.push_back('\t'); break;
case ('\'') : match.push_back('\''); break;
case ('\"') : match.push_back('\"'); break;
default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename);
bool is_interpolated = false;
bool saw_interpolation_marker = false;
int prev_stack_top = match_stack.size();
//for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) {
std::string::iterator s = start + 1, end = input_pos - 1;
while (s != end) {
if (saw_interpolation_marker) {
if (*s == '{') {
//We've found an interpolation point
if (is_interpolated) {
//If we've seen previous interpolation, add on instead of making a new one
TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col));
match_stack.push_back(plus);
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
build_match(Token_Type::Additive, prev_stack_top);
}
else {
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
}
//We've finished with the part of the string up to this point, so clear it
match = "";
TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col));
match_stack.push_back(plus);
std::string eval_match;
++s;
while ((*s != '}') && (s != end)) {
eval_match.push_back(*s);
++s;
}
if (*s == '}') {
is_interpolated = true;
++s;
int tostr_stack_top = match_stack.size();
TokenPtr tostr(new Token("to_string", Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(tostr);
int ev_stack_top = match_stack.size();
TokenPtr ev(new Token("eval", Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(ev);
int arg_stack_top = match_stack.size();
TokenPtr t(new Token(eval_match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
build_match(Token_Type::Arg_List, arg_stack_top);
build_match(Token_Type::Inplace_Fun_Call, ev_stack_top);
build_match(Token_Type::Arg_List, ev_stack_top);
build_match(Token_Type::Fun_Call, tostr_stack_top);
build_match(Token_Type::Additive, prev_stack_top);
}
else {
throw Eval_Error("Unclosed in-string eval", File_Position(prev_line, prev_col), filename);
}
}
else {
match.push_back(*s);
match.push_back('$');
}
is_escaped = false;
saw_interpolation_marker = false;
}
else {
if (*s == '\\') {
if (is_escaped) {
match.push_back('\\');
is_escaped = false;
}
else {
is_escaped = true;
}
}
else {
if (is_escaped) {
switch (*s) {
case ('b') : match.push_back('\b'); break;
case ('f') : match.push_back('\f'); break;
case ('n') : match.push_back('\n'); break;
case ('r') : match.push_back('\r'); break;
case ('t') : match.push_back('\t'); break;
case ('\'') : match.push_back('\''); break;
case ('\"') : match.push_back('\"'); break;
case ('$') : match.push_back('$'); break;
default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename);
}
}
else if (*s == '$') {
saw_interpolation_marker = true;
}
else {
match.push_back(*s);
}
is_escaped = false;
}
++s;
}
}
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
if (is_interpolated) {
TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col));
match_stack.push_back(plus);
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
build_match(Token_Type::Additive, prev_stack_top);
}
else {
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
}
return true;
}
else {
@@ -591,7 +787,7 @@ namespace chaiscript
/**
* Reads (and potentially captures) a symbol group from input if it matches the parameter
*/
bool Symbol(const char *s, bool capture = false) {
bool Symbol(const char *s, bool capture = false, bool disallow_prevention=false) {
SkipWS();
if (!capture) {
@@ -601,7 +797,7 @@ namespace chaiscript
bool retval = Symbol_(s);
if (retval) {
//todo: fix this. Hacky workaround for preventing substring matches
if ((input_pos != input_end) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '=') || (*input_pos == '.'))) {
if ((input_pos != input_end) && (disallow_prevention == false) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '=') || (*input_pos == '.'))) {
input_pos = start;
col = prev_col;
line = prev_line;
@@ -619,7 +815,7 @@ namespace chaiscript
int prev_line = line;
if (Symbol_(s)) {
//todo: fix this. Hacky workaround for preventing substring matches
if ((input_pos != input_end) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '=') || (*input_pos == '.'))) {
if ((input_pos != input_end) && (disallow_prevention == false) && ((*input_pos == '+') || (*input_pos == '-') || (*input_pos == '*') || (*input_pos == '/') || (*input_pos == '=') || (*input_pos == '.'))) {
input_pos = start;
col = prev_col;
line = prev_line;
@@ -691,8 +887,10 @@ namespace chaiscript
if (Equation()) {
retval = true;
while (Eol());
if (Char(',')) {
do {
while (Eol());
if (!Equation()) {
throw Eval_Error("Unexpected value in parameter list", match_stack.back());
}
@@ -718,8 +916,10 @@ namespace chaiscript
}
else if (Map_Pair()) {
retval = true;
while (Eol());
if (Char(',')) {
do {
while (Eol());
if (!Map_Pair()) {
throw Eval_Error("Unexpected value in container", match_stack.back());
}
@@ -768,7 +968,7 @@ namespace chaiscript
bool Def() {
bool retval = false;
bool is_annotated = false;
bool is_method = false;
TokenPtr annotation;
if (Annotation()) {
@@ -787,6 +987,15 @@ namespace chaiscript
throw Eval_Error("Missing function name in definition", File_Position(line, col), filename);
}
if (Symbol("::", false)) {
//We're now a method
is_method = true;
if (!Id(true)) {
throw Eval_Error("Missing method name in definition", File_Position(line, col), filename);
}
}
if (Char('(')) {
Arg_List();
if (!Char(')')) {
@@ -807,7 +1016,12 @@ namespace chaiscript
throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
}
build_match(Token_Type::Def, prev_stack_top);
if (is_method) {
build_match(Token_Type::Method, prev_stack_top);
}
else {
build_match(Token_Type::Def, prev_stack_top);
}
if (is_annotated) {
match_stack.back()->annotation = annotation;
@@ -817,6 +1031,67 @@ namespace chaiscript
return retval;
}
/**
* Reads a function definition from input
*/
bool Try() {
bool retval = false;
int prev_stack_top = match_stack.size();
if (Keyword("try")) {
retval = true;
while (Eol());
if (!Block()) {
throw Eval_Error("Incomplete 'try' block", File_Position(line, col), filename);
}
bool has_matches = true;
while (has_matches) {
while (Eol());
has_matches = false;
if (Keyword("catch", false)) {
int catch_stack_top = match_stack.size();
if (Char('(')) {
if (!(Id(true) && Char(')'))) {
throw Eval_Error("Incomplete 'catch' expression", File_Position(line, col), filename);
}
if (Char(':')) {
if (!Expression()) {
throw Eval_Error("Missing guard expression for catch", File_Position(line, col), filename);
}
}
}
while (Eol());
if (!Block()) {
throw Eval_Error("Incomplete 'catch' block", File_Position(line, col), filename);
}
build_match(Token_Type::Catch, catch_stack_top);
has_matches = true;
}
}
while (Eol());
if (Keyword("finally", false)) {
int finally_stack_top = match_stack.size();
while (Eol());
if (!Block()) {
throw Eval_Error("Incomplete 'finally' block", File_Position(line, col), filename);
}
build_match(Token_Type::Finally, finally_stack_top);
}
build_match(Token_Type::Try, prev_stack_top);
}
return retval;
}
/**
* Reads an if/elseif/else block from input
*/
@@ -1022,7 +1297,7 @@ namespace chaiscript
std::string::iterator prev_pos = input_pos;
unsigned int prev_stack_top = match_stack.size();
if (Id(true) || Id_Literal()) {
if (Id(true)) {
retval = true;
bool has_more = true;
@@ -1071,6 +1346,22 @@ namespace chaiscript
build_match(Token_Type::Var_Decl, prev_stack_top);
}
else if (Keyword("attr")) {
retval = true;
if (!Id(true)) {
throw Eval_Error("Incomplete attribute declaration", File_Position(line, col), filename);
}
if (!Symbol("::", false)) {
throw Eval_Error("Incomplete attribute declaration", File_Position(line, col), filename);
}
if (!Id(true)) {
throw Eval_Error("Missing attribute name in definition", File_Position(line, col), filename);
}
build_match(Token_Type::Attr_Decl, prev_stack_top);
}
return retval;
}
@@ -1126,53 +1417,6 @@ namespace chaiscript
return retval;
}
/**
* Reads an identifier literal of the special form `<name>` from input
*/
bool Id_Literal() {
bool retval = false;
SkipWS();
if ((input_pos != input_end) && (*input_pos == '`')) {
retval = true;
int prev_col = col;
int prev_line = line;
++col;
++input_pos;
std::string::iterator start = input_pos;
while ((input_pos != input_end) && (*input_pos != '`')) {
if (Eol()) {
throw Eval_Error("Carriage return in identifier literal", File_Position(line, col), filename);
}
else {
++input_pos;
++col;
}
}
if (start == input_pos) {
throw Eval_Error("Missing contents of identifier literal", File_Position(line, col), filename);
}
else if (input_pos == input_end) {
throw Eval_Error("Incomplete identifier literal", File_Position(line, col), filename);
}
++col;
std::string match(start, input_pos);
TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col));
match_stack.push_back(t);
++input_pos;
}
return retval;
}
/**
* Reads a unary prefixed expression from input
*/
@@ -1181,24 +1425,6 @@ namespace chaiscript
int prev_stack_top = match_stack.size();
if (Symbol("-")) {
retval = true;
if (!Dot_Access()) {
throw Eval_Error("Incomplete negation expression", File_Position(line, col), filename);
}
build_match(Token_Type::Negate, prev_stack_top);
}
else if (Symbol("!")) {
retval = true;
if (!Dot_Access()) {
throw Eval_Error("Incomplete '!' expression", File_Position(line, col), filename);
}
build_match(Token_Type::Not, prev_stack_top);
}
if (Symbol("++", true)) {
retval = true;
@@ -1217,6 +1443,24 @@ namespace chaiscript
build_match(Token_Type::Prefix, prev_stack_top);
}
else if (Char('-')) {
retval = true;
if (!Dot_Access()) {
throw Eval_Error("Incomplete negation expression", File_Position(line, col), filename);
}
build_match(Token_Type::Negate, prev_stack_top);
}
else if (Char('!')) {
retval = true;
if (!Dot_Access()) {
throw Eval_Error("Incomplete '!' expression", File_Position(line, col), filename);
}
build_match(Token_Type::Not, prev_stack_top);
}
return retval;
}
@@ -1242,11 +1486,11 @@ namespace chaiscript
int prev_stack_top = match_stack.size();
if (Additive()) {
if (Shift()) {
retval = true;
if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) {
do {
if (!Additive()) {
if (!Shift()) {
throw Eval_Error("Incomplete comparison expression", File_Position(line, col), filename);
}
} while (retval && (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)));
@@ -1330,6 +1574,30 @@ namespace chaiscript
return retval;
}
/**
* Top-level expression, parses a string of binary boolean operators from input
*/
bool Shift() {
bool retval = false;
int prev_stack_top = match_stack.size();
if (Additive()) {
retval = true;
if (Symbol("<<", true) || Symbol(">>", true)) {
do {
if (!Additive()) {
throw Eval_Error("Incomplete shift expression", File_Position(line, col), filename);
}
} while (retval && (Symbol("<<", true) || Symbol(">>", true)));
build_match(Token_Type::Shift, prev_stack_top);
}
}
return retval;
}
/**
* Top-level expression, parses a string of binary boolean operators from input
*/
@@ -1419,7 +1687,8 @@ namespace chaiscript
if (Expression()) {
retval = true;
if (Symbol("=", true) || Symbol(":=", true) || Symbol("+=", true) || Symbol("-=", true) || Symbol("*=", true) || Symbol("/=", true)) {
if (Symbol("=", true, true) || Symbol(":=", true, true) || Symbol("+=", true, true) ||
Symbol("-=", true, true) || Symbol("*=", true, true) || Symbol("/=", true, true)) {
if (!Equation()) {
throw Eval_Error("Incomplete equation", match_stack.back());
}
@@ -1450,6 +1719,14 @@ namespace chaiscript
retval = true;
saw_eol = true;
}
else if (Try()) {
if (!saw_eol) {
throw Eval_Error("Two function definitions missing line separator", match_stack.back());
}
has_more = true;
retval = true;
saw_eol = true;
}
else if (If()) {
if (!saw_eol) {
throw Eval_Error("Two function definitions missing line separator", match_stack.back());
@@ -1503,6 +1780,11 @@ namespace chaiscript
retval = true;
saw_eol = true;
}
else if (Block()) {
has_more = true;
retval = true;
saw_eol = true;
}
else {
has_more = false;
}

View File

@@ -12,274 +12,318 @@
#define CODE_STRING(x, y) #x ", " #y
#define chaiscript_prelude CODE_STRING(\
def new(x) { eval(type_name(x))(); } \
def clone(x) { eval(type_name(x))(x); } \
def lt(l, r) { if (call_exists(`<`, l, r)) { l < r } else { type_name(l) < type_name(r) } } \n\
def gt(l, r) { if (call_exists(`>`, l, r)) { l > r } else { type_name(l) > type_name(r) } } \n\
def eq(l, r) { if (call_exists(`==`, l, r)) { l == r } else { false } } \n\
def new(x) { eval(type_name(x))(); } \n\
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x) { eval(type_name(x))(x); } \n\
# 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() + ">"; \
}\
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \n\
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \n\
}\n\
# to_string for containers\n\
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \
"[" + x.join(", ") + "]"; \
}\
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \n\
"[" + x.join(", ") + "]"; \n\
}\n\
# Basic to_string function\n\
def to_string(x) { \
internal_to_string(x); \
}\
def to_string(x) { \n\
internal_to_string(x); \n\
}\n\
# Prints to console with no carriage return\n\
def puts(x) { \
print_string(x.to_string()); \
} \
def puts(x) { \n\
print_string(x.to_string()); \n\
} \n\
# Prints to console with carriage return\n\
def print(x) { \
println_string(x.to_string()); \
} \
def print(x) { \n\
println_string(x.to_string()); \n\
} \n\
# Returns the maximum value of two numbers\n\
def max(a, b) { if (a>b) { a } else { b } } \
def max(a, b) { if (a>b) { a } else { b } } \n\
# Returns the minimum value of two numbers\n\
def min(a, b) { if (a<b) { a } else { b } } \
def min(a, b) { if (a<b) { a } else { b } } \n\
# Returns true if the value is odd\n\
def odd(x) { if (x % 2 == 1) { true } else { false } } \
def odd(x) { if (x % 2 == 1) { true } else { false } } \n\
# Returns true if the value is even\n\
def even(x) { if (x % 2 == 0) { true } else { false } } \
def even(x) { if (x % 2 == 0) { true } else { false } } \n\
# Pushes the second value onto the container first value while making a clone of the value\n\
def push_back(container, x) : call_exists(push_back_ref, container, x) { container.push_back_ref(clone(x)) } \n\
# Pushes the second value onto the front of the container first value while making a clone of the value\n\
def push_front(container, x) : call_exists(push_front_ref, container, x) { container.push_front_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\
# Returns the reverse of the given container\n\
def reverse(container) {\
var retval = new(container); \
var r = retro(range(container)); \
while (!r.empty()) { \
retval.push_back(r.front()); \
r.pop_front(); \
} \
retval; \
} \
def reverse(container) {\n\
var retval = new(container); \n\
var r = range(container); \n\
while (!r.empty()) { \n\
retval.push_back(r.back()); \n\
r.pop_back(); \n\
} \n\
retval; \n\
} \n\
# Return a range from a range \n\
def range(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { return clone(r); }\n\
# The retro attribute that contains the underlying range \n\
attr retro::m_range; \n\
# Creates a retro from a retro by returning the original range\n\
def retro(r) : call_exists(get_type_name, r) && get_type_name(r) == "retro" { clone(r.m_range) }\n\
# Creates a retro range from a range\n\
def retro::retro(r) : call_exists(empty, r) && call_exists(pop_front, r) && call_exists(pop_back, r) && call_exists(back, r) && call_exists(front, r) { this.m_range = r; }\n\
# Returns the first value of a retro\n\
def retro::front() { back(this.m_range) }\n\
# Returns the last value of a retro\n\
def retro::back() { front(this.m_range) }\n\
# Moves the back iterator of a retro towards the front by one \n\
def retro::pop_back() { pop_front(this.m_range) }\n\
# Moves the front iterator of a retro towards the back by one \n\
def retro::pop_front() { pop_back(this.m_range) } \n\
# returns true if the retro is out of elements \n\
def retro::empty() { empty(this.m_range); } \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) { \
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(); \
} \
} \
def for_each(container, func) : call_exists(range, container) { \n\
var t_range = range(container); \n\
while (!t_range.empty()) { \n\
func(t_range.front()); \n\
t_range.pop_front(); \n\
} \n\
} \n\
def back_inserter(container) { \n\
bind(push_back, container, _); \n\
}\n\
\n\
def contains(container, item, compare_func) : call_exists(range, container) { \n\
var t_range = range(container); \n\
while (!t_range.empty()) { \n\
if ( compare_func(t_range.front(), item) ) { return true; } \n\
t_range.pop_front(); \n\
} \n\
return false; \n\
} \n\
def contains(container, item) { return contains(container, item, eq) } \n\
def map(container, func, inserter) : call_exists(range, container) { \n\
var range = range(container); \n\
while (!range.empty()) { \n\
inserter(func(range.front())); \n\
range.pop_front(); \n\
} \n\
} \n\
# Performs the second value function over the container first value. Creates a new container with the results\n\
def map(container, func) { \
var retval = new(container); \
map(container, func, back_inserter(retval));\
retval;\
}\
def map(container, func) { \n\
var retval = new(container); \n\
map(container, func, back_inserter(retval));\n\
retval;\n\
}\n\
# 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; \
} \
def foldl(container, func, initial) : call_exists(range, container){ \n\
var retval = initial; \n\
var range = range(container); \n\
while (!range.empty()) { \n\
retval = (func(range.front(), retval)); \n\
range.pop_front(); \n\
} \n\
retval; \n\
} \n\
# Returns the sum of the elements of the given value\n\
def sum(container) { foldl(container, `+`, 0.0) } \
def sum(container) { foldl(container, `+`, 0.0) } \n\
# Returns the product of the elements of the given value\n\
def product(container) { foldl(container, `*`, 1.0) } \
def product(container) { foldl(container, `*`, 1.0) } \n\
# Returns a new container 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; \
} \
} \
def concat(x, y) : call_exists(clone, x) { \n\
var retval = x; \n\
var len = y.size(); \n\
var i = 0; \n\
while (i < len) { \n\
retval.push_back(y[i]); \n\
++i; \n\
} \n\
retval; \n\
} \n\
def take(container, num, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
var i = num; \n\
while ((i > 0) && (!r.empty())) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
--i; \n\
} \n\
} \n\
# Returns a new container with the given number of elements taken from the container\n\
def take(container, num) {\
var retval = new(container); \
take(container, num, back_inserter(retval)); \
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(); \
} \
} \
def take(container, num) {\n\
var retval = new(container); \n\
take(container, num, back_inserter(retval)); \n\
retval; \n\
}\n\
def take_while(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
while ((!r.empty()) && f(r.front())) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
} \n\
} \n\
# Returns a new container with the given elements match the second value function\n\
def take_while(container, f) {\
var retval = new(container); \
take_while(container, f, back_inserter(retval)); \
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(); \
} \
} \
def take_while(container, f) {\n\
var retval = new(container); \n\
take_while(container, f, back_inserter(retval)); \n\
retval;\n\
}\n\
def drop(container, num, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
var i = num; \n\
while ((i > 0) && (!r.empty())) { \n\
r.pop_front(); \n\
--i; \n\
} \n\
while (!r.empty()) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
} \n\
} \n\
# Returns a new container with the given number of elements dropped from the given container \n\
def drop(container, num) {\
var retval = new(container); \
drop(container, num, back_inserter(retval)); \
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(); \
} \
} \
def drop(container, num) {\n\
var retval = new(container); \n\
drop(container, num, back_inserter(retval)); \n\
retval; \n\
}\n\
def drop_while(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
while ((!r.empty())&& f(r.front())) { \n\
r.pop_front(); \n\
} \n\
while (!r.empty()) { \n\
inserter(r.front()); \n\
r.pop_front(); \n\
} \n\
} \n\
# Returns a new container with the given elements dropped that match the second value function\n\
def drop_while(container, f) {\
var retval = new(container); \
drop_while(container, f, back_inserter(retval)); \
retval; \
}\
def drop_while(container, f) {\n\
var retval = new(container); \n\
drop_while(container, f, back_inserter(retval)); \n\
retval; \n\
}\n\
# 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; \
} \
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
var r = range(container); \n\
var retval = r.front(); \n\
r.pop_front(); \n\
retval = func(retval, r.front()); \n\
r.pop_front(); \n\
while (!r.empty()) { \n\
retval = func(retval, r.front()); \n\
r.pop_front(); \n\
} \n\
retval; \n\
} \n\
# 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(); \
} \
} \
def join(container, delim) { \n\
var retval = ""; \n\
var range = range(container); \n\
if (!range.empty()) { \n\
retval += to_string(range.front()); \n\
range.pop_front(); \n\
while (!range.empty()) { \n\
retval += delim; \n\
retval += to_string(range.front()); \n\
range.pop_front(); \n\
} \n\
} \n\
retval; \n\
} \n\
def filter(container, f, inserter) : call_exists(range, container) { \n\
var r = range(container); \n\
while (!r.empty()) { \n\
if (f(r.front())) { \n\
inserter(r.front()); \n\
} \n\
r.pop_front(); \n\
} \n\
} \n\
# Returns a new Vector which match the second value function\n\
def filter(container, f) { \
var retval = new(container); \
filter(container, f, back_inserter(retval));\
retval;\
}\
def generate_range(x, y, inserter) { \
var i = x; \
while (i <= y) { \
inserter(i); \
++i; \
} \
} \
def filter(container, f) { \n\
var retval = new(container); \n\
filter(container, f, back_inserter(retval));\n\
retval;\n\
}\n\
def generate_range(x, y, inserter) { \n\
var i = x; \n\
while (i <= y) { \n\
inserter(i); \n\
++i; \n\
} \n\
} \n\
# 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)); \
retval; \
}\
def generate_range(x, y) { \n\
var retval = Vector(); \n\
generate_range(x,y,back_inserter(retval)); \n\
retval; \n\
}\n\
# 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(); \
} \
} \
def collate(x, y) { \n\
[x, y]; \n\
} \n\
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
var r_x = range(x); \n\
var r_y = range(y); \n\
while (!r_x.empty() && !r_y.empty()) { \n\
inserter(f(r_x.front(), r_y.front())); \n\
r_x.pop_front(); \n\
r_y.pop_front(); \n\
} \n\
} \n\
# 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)); \
retval;\
}\
def zip_with(f, x, y) { \n\
var retval = Vector(); \n\
zip_with(f,x,y,back_inserter(retval)); \n\
retval;\n\
}\n\
# Returns a new Vector which joins matching elements of the first and second\n\
def zip(x, y) { \
zip_with(collate, x, y); \
}\
def zip(x, y) { \n\
zip_with(collate, x, y); \n\
}\n\
# Returns the position of the second value string in the first value string\n\
def find(str, substr) { \
int(find(str, substr, size_t(0))); \
} \
def string::find(substr) : is_type(substr, "string") { \n\
int(find(this, substr, size_t(0))); \n\
} \n\
# Returns the position of last match of the second value string in the first value string\n\
def rfind(str, substr) { \
int(rfind(str, substr, size_t(-1))); \
} \
def string::rfind(substr) : is_type(substr, "string") { \n\
int(rfind(this, substr, size_t(-1))); \n\
} \n\
# 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) { \
int(find_first_of(str, list, size_t(0))); \
} \
def string::find_first_of(list) : is_type(list, "string") { \n\
int(find_first_of(this, list, size_t(0))); \n\
} \n\
# 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) { \
int(find_last_of(str, list, size_t(-1))); \
} \
def string::find_last_of(list) : is_type(list, "string") { \n\
int(find_last_of(this, list, size_t(-1))); \n\
} \n\
# 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) { \
int(find_first_not_of(str, list, size_t(0))); \
} \
def string::find_first_not_of(list) : is_type(list, "string") { \n\
int(find_first_not_of(this, list, size_t(0))); \n\
} \n\
# 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) { \
int(find_last_not_of(str, list, size_t(-1))); \
} \
def ltrim(str) { \
drop_while(str, fun(x) { x == ' ' || x == '\t' }); \
} \
def rtrim(str) { \
reverse(drop_while(reverse(str), fun(x) { x == ' ' || x == '\t' })); \
} \
def trim(str) { \
ltrim(rtrim(str)); \
} \
def string::find_last_not_of(list) : is_type(list, "string") { \n\
int(find_last_not_of(this, list, size_t(-1))); \n\
} \n\
def string::ltrim() { \n\
drop_while(this, fun(x) { x == ' ' || x == '\t' }); \n\
} \n\
def string::rtrim() { \n\
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' })); \n\
} \n\
def string::trim() { \n\
ltrim(rtrim(this)); \n\
} \n\
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "function") { \n\
var range = range(container); \n\
while (!range.empty()) { \n\
if (compare_func(range.front(), value)) { \n\
return range; \n\
} else { \n\
range.pop_front(); \n\
} \n\
} \n\
return range; \n\
} \n\
def find(container, value) { return find(container, value, eq) } \
)
#endif /* CHAISCRIPT_PRELUDE_HPP_ */

View File

@@ -42,7 +42,7 @@
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="C:\Programming\chaiscript\trunk\include"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
MinimalRebuild="true"
BasicRuntimeChecks="3"
@@ -117,6 +117,7 @@
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"

View File

@@ -6,7 +6,7 @@
>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;C:\Programming\Boost\include\boost-1_38&quot;"
AdditionalIncludeDirectories="&quot;C:\boost\include\boost-1_38&quot;"
/>
<Tool
Name="VCLibrarianTool"
@@ -14,6 +14,6 @@
/>
<Tool
Name="VCLinkerTool"
AdditionalLibraryDirectories="C:\Programming\Boost\lib"
AdditionalLibraryDirectories="C:\Boost\lib"
/>
</VisualStudioPropertySheet>

View File

@@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vc
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chai-example", "..\chai-example\chai-example.vcproj", "{CE422E94-B360-4588-8C65-6A9BE80798F9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module", "..\test_module\test_module.vcproj", "{775EDCC2-102F-4E75-A860-9AF398D04145}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -19,6 +21,10 @@ Global
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Debug|Win32.Build.0 = Debug|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.ActiveCfg = Release|Win32
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.Build.0 = Release|Win32
{775EDCC2-102F-4E75-A860-9AF398D04145}.Debug|Win32.ActiveCfg = Debug|Win32
{775EDCC2-102F-4E75-A860-9AF398D04145}.Debug|Win32.Build.0 = Debug|Win32
{775EDCC2-102F-4E75-A860-9AF398D04145}.Release|Win32.ActiveCfg = Release|Win32
{775EDCC2-102F-4E75-A860-9AF398D04145}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -23,7 +23,7 @@
ConfigurationType="1"
InheritedPropertySheets=".\Boost.vsprops"
UseOfMFC="2"
CharacterSet="0"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
@@ -49,7 +49,7 @@
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
DisableLanguageExtensions="true"
DisableLanguageExtensions="false"
TreatWChar_tAsBuiltInType="false"
UsePrecompiledHeader="0"
WarningLevel="4"
@@ -100,7 +100,7 @@
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
InheritedPropertySheets=".\Boost.vsprops"
CharacterSet="0"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
@@ -122,7 +122,7 @@
Name="VCCLCompilerTool"
Optimization="3"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\dispatchkit&quot;;&quot;$(ProjectDir)\..\..\chaiscript&quot;"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
@@ -221,14 +221,30 @@
RelativePath="..\..\include\chaiscript\language\chaiscript_prelude.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\chaiscript_threading.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\dispatchkit.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\dynamic_object.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\function_call_detail.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\handle_return.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_constructors.hpp"
>
@@ -237,6 +253,10 @@
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\proxy_functions_detail.hpp"
>
</File>
<File
RelativePath="..\..\include\chaiscript\dispatchkit\register_function.hpp"
>

View File

@@ -0,0 +1,198 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="test_module"
ProjectGUID="{775EDCC2-102F-4E75-A860-9AF398D04145}"
RootNamespace="test_module"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
UseOfMFC="0"
CharacterSet="0"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;TEST_MODULE_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="2"
GenerateDebugInformation="true"
SubSystem="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="2"
InheritedPropertySheets="..\chaiscript\Boost.vsprops"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\..\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;TEST_MODULE_EXPORTS"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath="..\..\src\test_module.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@@ -1,5 +1,6 @@
#!/bin/bash
successes=0
failures=0
@@ -8,7 +9,7 @@ for file in unittests/*.chai
do
tstname=${file%.*}
tst="$tstname.txt"
./chaiscript_eval $file > /tmp/tstout.txt
LD_LIBRARY_PATH=. ./chaiscript_eval $file > /tmp/tstout.txt
diff $tst /tmp/tstout.txt
if [ "$?" -eq "0" ]
then

27
run_unit_tests_win.sh Normal file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
successes=0
failures=0
echo -n "Running unit tests"
for file in unittests/*.chai
do
tstname=${file%.*}
tst="$tstname.txt"
./chaiscript_eval $file > /tmp/tstout.txt
cat $tst > /tmp/tstmaster.txt
awk 'sub("$", "\r")' $tst > /tmp/tstmaster.txt
diff /tmp/tstmaster.txt /tmp/tstout.txt
if [ "$?" -eq "0" ]
then
echo -n "."
successes=$((successes+1))
else
echo "[from failed test $file]"
failures=$((failures+1))
fi
done
echo ""
total=$((successes+failures))
echo "$successes out of $total succeeded"

View File

@@ -22,6 +22,22 @@ void log(const std::string &module, const std::string &msg)
std::cout << "[" << boost::posix_time::microsec_clock::local_time() << "] <" << module << "> " << msg << std::endl;
}
void bound_log(const std::string &msg)
{
log(msg);
}
void hello_world(const chaiscript::Boxed_Value &o)
{
std::cout << "Hello World" << std::endl;
}
void hello_constructor(const chaiscript::Boxed_Value &o)
{
std::cout << "Hello Constructor" << std::endl;
}
struct System
{
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
@@ -45,6 +61,10 @@ struct System
}
};
void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
{
std::cout << *p << std::endl;
}
int main(int argc, char *argv[]) {
using namespace chaiscript;
@@ -55,10 +75,15 @@ int main(int argc, char *argv[]) {
System system;
chai.add(var(&system), "system");
//Add a bound callback method
chai.add(fun(&System::add_callback, system), "add_callback_bound");
//Register the two methods of the System structure.
chai.add(fun(&System::add_callback), "add_callback");
chai.add(fun(&System::do_callbacks), "do_callbacks");
chai.add(fun(&take_shared_ptr), "take_shared_ptr");
// Let's use chaiscript to add a new lambda callback to our system.
// The function "{ 'Callback1' + x }" is created in chaiscript and passed into our C++ application
// in the "add_callback" function of struct System the chaiscript function is converted into a
@@ -85,7 +110,7 @@ int main(int argc, char *argv[]) {
//Finally, it is possible to register any boost::function as a system function, in this
//way, we can, for instance add a bound member function to the system
chai.add(fun(boost::function<void ()>(boost::bind(&System::do_callbacks, boost::ref(system), "Bound Test"))), "do_callbacks");
chai.add(fun(&System::do_callbacks, boost::ref(system), "Bound Test"), "do_callbacks");
//Call bound version of do_callbacks
chai("do_callbacks()");
@@ -123,5 +148,20 @@ int main(int argc, char *argv[]) {
//mostly supported currently
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
// Test ability to register a function that excepts a shared_ptr version of a type
chai("take_shared_ptr(\"Hello World as a shared_ptr\");");
chai.add(fun(&bound_log, std::string("Msg")), "BoundFun");
//Dynamic objects test
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Function("TestType", fun(&hello_world))), "hello_world");
chai.add(chaiscript::Proxy_Function(new Dynamic_Object_Constructor("TestType", fun(&hello_constructor))), "TestType");
chai.add(fun(boost::function<Boxed_Value (Dynamic_Object &)>(boost::bind(&Dynamic_Object_Attribute::func, "TestType", "attr", _1))), "attr");
chai.eval("var x = TestType()");
chai.eval("x.attr = \"hi\"");
chai.eval("print(x.attr)");
chai.eval("x.hello_world()");
}

View File

@@ -6,22 +6,48 @@
#include <iostream>
#include <list>
#ifdef READLINE_AVAILABLE
#include <readline/readline.h>
#include <readline/history.h>
#endif
#include <chaiscript/chaiscript.hpp>
void print_help() {
std::cout << "ChaiScript evaluator. To evaluate and expression, type it and press <enter>." << std::endl;
std::cout << "ChaiScript evaluator. To evaluate an expression, type it and press <enter>." << std::endl;
std::cout << "Additionally, you can inspect the runtime system using:" << std::endl;
std::cout << " dump_system() - outputs all functions registered to the system" << std::endl;
std::cout << " dump_object(x) - dumps information about the given symbol" << std::endl;
}
std::string get_next_command() {
#ifdef READLINE_AVAILABLE
char *input_raw;
input_raw = readline("eval> ");
add_history(input_raw);
return std::string(input_raw);
#else
std::string retval;
std::cout << "eval> ";
std::getline(std::cin, retval);
return retval;
#endif
}
int main(int argc, char *argv[]) {
std::string input;
chaiscript::ChaiScript chai;
if (argc < 2) {
std::cout << "eval> ";
std::getline(std::cin, input);
//std::cout << "eval> ";
//std::getline(std::cin, input);
#ifdef READLINE_AVAILABLE
using_history();
#endif
input = get_next_command();
while (input != "quit") {
chaiscript::Boxed_Value val;
@@ -35,7 +61,7 @@ int main(int argc, char *argv[]) {
val = chai.eval(input);
//Then, we try to print the result of the evaluation to the user
if (val.get_type_info().m_bare_type_info && *(val.get_type_info().m_bare_type_info) != typeid(void)) {
if (!val.get_type_info().bare_equal(chaiscript::user_type<void>())) {
try {
chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
}
@@ -49,8 +75,7 @@ int main(int argc, char *argv[]) {
}
}
std::cout << "eval> ";
std::getline(std::cin, input);
input = get_next_command();
}
}
else {

38
src/multithreaded.cpp Normal file
View File

@@ -0,0 +1,38 @@
// This file is distributed under the BSD License.
// See "license.txt" for details.
// Copyright 2009, Jonathan Turner (jturner@minnow-lang.org)
// and Jason Turner (lefticus@gmail.com)
// http://www.chaiscript.com
#include <iostream>
#include <list>
#include <chaiscript/chaiscript.hpp>
#include <boost/thread.hpp>
void do_work(chaiscript::ChaiScript &c)
{
// c("use(\"work.chai\"); do_chai_work(num_iterations);");
c("use(\"work.chai\"); do_chai_work(10000);");
}
int main(int argc, char *argv[]) {
std::string input;
chaiscript::ChaiScript chai;
//chai.add_shared_object(chaiscript::Boxed_Value(10000), "num_iterations");
std::vector<boost::shared_ptr<boost::thread> > threads;
for (int i = 0; i < argc - 1; ++i)
{
threads.push_back(boost::shared_ptr<boost::thread>(new boost::thread(boost::bind(do_work, boost::ref(chai)))));
}
for (int i = 0; i < argc - 1; ++i)
{
threads[i]->join();
}
}

9
src/stl_extra.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_stl_extra()
{
return chaiscript::bootstrap::list_type<std::list<chaiscript::Boxed_Value> >("List");
}

16
src/test_module.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <chaiscript/chaiscript.hpp>
#include <string>
std::string hello_world()
{
return "Hello World";
}
CHAISCRIPT_MODULE_EXPORT chaiscript::ModulePtr create_chaiscript_module_test()
{
chaiscript::ModulePtr m(new chaiscript::Module());
m->add(chaiscript::fun(hello_world), "hello_world");
return m;
}

10
src/work.chai Normal file
View File

@@ -0,0 +1,10 @@
def do_chai_work(num_iters)
{
var i = 0;
for (var k = 0; k<num_iters * 10; ++k)
{
i += k;
}
print(i);
}

View File

@@ -0,0 +1 @@
{print("hello")}

View File

@@ -0,0 +1 @@
hello

View File

@@ -0,0 +1,4 @@
var x=.5
print(x)
var y=-.5
print(y)

View File

@@ -0,0 +1,2 @@
0.5
-0.5

9
unittests/exception.chai Normal file
View File

@@ -0,0 +1,9 @@
var x = 1
try {
throw(x)
x = 2
}
catch(e) {
x = e + 3
}
print(x)

1
unittests/exception.txt Normal file
View File

@@ -0,0 +1 @@
4

View File

@@ -0,0 +1,19 @@
try {
throw(3)
}
catch(x) {
print(x)
}
finally {
print("Finally #1")
}
try {
print("Safe")
}
catch {
print("Caught")
}
finally {
print("Finally #2")
}

View File

@@ -0,0 +1,4 @@
3
Finally #1
Safe
Finally #2

View File

@@ -0,0 +1,28 @@
for (var i = 2; i < 6; ++i) {
try {
throw(i)
}
catch(e) : e < 2 {
print("Catch 1: " + e.to_string())
}
catch(e) : e < 4 {
print("Catch 2: " + e.to_string())
}
catch(e) {
print("Catch 3: " + e.to_string())
}
catch {
print("This is never called")
}
}
try {
throw(3)
}
catch(e) : e < 3
{
print("Caught less than 3")
}
catch {
print("Backup catch")
}

View File

@@ -0,0 +1,5 @@
Catch 2: 2
Catch 2: 3
Catch 3: 4
Catch 3: 5
Backup catch

2
unittests/float.chai Normal file
View File

@@ -0,0 +1,2 @@
print(1.2)
print(.5)

2
unittests/float.txt Normal file
View File

@@ -0,0 +1,2 @@
1.2
0.5

View File

@@ -0,0 +1,3 @@
var v = [1,2,3];
var r = range(v);
for_each(r, print)

View File

@@ -0,0 +1,3 @@
1
2
3

View File

@@ -0,0 +1,3 @@
var v = [1,2,3];
var r = retro(range(v));
for_each(r, print)

View File

@@ -0,0 +1,3 @@
3
2
1

View File

@@ -0,0 +1,3 @@
var x = `+`
x = `-`
print(x(5,4))

View File

@@ -0,0 +1 @@
1

View File

@@ -0,0 +1,3 @@
var bob = 5.5
print("${bob}")
print("val: ${5.5 + 2.5} and ${bob + 2.5}")

View File

@@ -0,0 +1,2 @@
5.5
val: 8 and 8

View File

@@ -0,0 +1,4 @@
print("$ {4 + 5}")
print("$${4+5}")
print("Value: \${4 + 5}")
print("Value: \$${4 + 5}")

View File

@@ -0,0 +1,4 @@
$ {4 + 5}
$9
Value: ${4 + 5}
Value: $9

View File

@@ -0,0 +1 @@
clone = `-`

View File

@@ -0,0 +1 @@
Error: "Mismatched types in equation" in 'unittests/invalid_function_assignment.chai' at (1, 7)

View File

@@ -0,0 +1,2 @@
var x = 5
x = `-`

View File

@@ -0,0 +1 @@
Error: "Mismatched types in equation" in 'unittests/invalid_function_reassignment.chai' at (2, 3)

View File

@@ -0,0 +1,6 @@
load_module("stl_extra")
var x = List()
x.push_back(3)
x.push_back("A")
print(x)

View File

@@ -0,0 +1 @@
[3, A]

View File

@@ -0,0 +1,6 @@
load_module("stl_extra")
var x = List()
x.push_front(3)
x.push_front("A")
print(x)

View File

@@ -0,0 +1 @@
[A, 3]

View File

@@ -0,0 +1,2 @@
load_module("test")
print(hello_world())

View File

@@ -0,0 +1 @@
Hello World

View File

@@ -0,0 +1,10 @@
var total = 0
for (var i = 0; i < 10; ++i) {
for (var j = 0; j < 10; ++j) {
total += 1
}
}
print(total)

View File

@@ -0,0 +1 @@
100

View File

@@ -1 +1,2 @@
print(--3)
var i = 3
print(--i)

View File

@@ -1 +1,2 @@
print(++3)
var i = 3
print(++i)

View File

@@ -0,0 +1,3 @@
var addit = fun(x, y) { return x+y }
print(3.addit(4))

View File

@@ -0,0 +1 @@
7

7
unittests/multiline.chai Normal file
View File

@@ -0,0 +1,7 @@
var x = [1, 2,
3, 4]
print(x)
print(map(x,
fun(x) { x + 1 }))

2
unittests/multiline.txt Normal file
View File

@@ -0,0 +1,2 @@
[1, 2, 3, 4]
[2, 3, 4, 5]

View File

@@ -0,0 +1,2 @@
print(012)
print(0x1f)

View File

@@ -0,0 +1,2 @@
10
31

View File

@@ -0,0 +1,5 @@
attr bob::z
def bob::bob() { this.z = 10 }
var x = bob()
def bob::fred(x) { this.z - x }
print(x.fred(3))

View File

@@ -0,0 +1 @@
7

View File

@@ -0,0 +1,11 @@
attr bob::z
def bob::bob() { }
var x = bob();
x.z = 10;
var y = clone(x);
y.z = 20;
print(x.z);
print(y.z);

View File

@@ -0,0 +1,2 @@
10
20

View File

@@ -0,0 +1,5 @@
def bob::bob(x) : x < 10 { print("constructed less than 10: " + x.to_string()) }
def bob::bob(x) { print("constructed any old: " + x.to_string()) }
var b = bob(12)
var c = bob(3)

View File

@@ -0,0 +1,2 @@
constructed any old: 12
constructed less than 10: 3

View File

@@ -0,0 +1,7 @@
def bob::bob() { }
def bob::fred(e) : e < 10 { print("e less than 10") }
def bob::fred(e) { print("e is some value") }
var b = bob()
b.fred(3)
b.fred(12)

View File

@@ -0,0 +1,2 @@
e less than 10
e is some value

View File

@@ -0,0 +1,8 @@
def Bob::`+`(y) { this.x + y.x }
def Bob::Bob() { }
attr Bob::x
var b = Bob()
var c = Bob()
b.x = 4
c.x = 5
print(b+c)

View File

@@ -0,0 +1 @@
9

View File

@@ -0,0 +1,8 @@
def Bob::Bob() { }
attr Bob::x
def `-`(a, b) : is_type(a, "Bob") && is_type(b, "Bob") { a.x - b.x }
var b = Bob()
var c = Bob()
b.x = 4
c.x = 5
print(b-c)

View File

@@ -0,0 +1 @@
-1

View File

@@ -0,0 +1,5 @@
var v = [1,2,"hi", "world", 5.5]
print(v.contains(5.5));
print(v.contains(0));
print(v.contains(1, lt));
print(v.contains(2, `==`));

View File

@@ -0,0 +1,4 @@
true
false
false
true

View File

@@ -0,0 +1,5 @@
var v = [2, 1, "Hi", 5.5]
var r = v.find("Hi");
print(r);
var r2 = v.find(2, `<`);
print(r2);

2
unittests/range_find.txt Normal file
View File

@@ -0,0 +1,2 @@
[Hi, 5.5]
[1, Hi, 5.5]

4
unittests/ref_equal.chai Normal file
View File

@@ -0,0 +1,4 @@
var i = 3
var j := i
j = 4
print(i)

1
unittests/ref_equal.txt Normal file
View File

@@ -0,0 +1 @@
4

View File

@@ -0,0 +1,7 @@
var x = [1, 2, 3, 4]
var r = retro(range(x))
r.pop_back()
var r2 = retro(r)
r2.pop_front()
print(r.back())
print(r2.front())

2
unittests/retroretro.txt Normal file
View File

@@ -0,0 +1,2 @@
2
3

View File

@@ -0,0 +1,6 @@
try {
throw(runtime_error("error"))
}
catch(e) {
print(e.what())
}

Some files were not shown because too many files have changed in this diff Show More