Compare commits
87 Commits
Release-1.
...
v2.1.0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d2d752ecd4 | ||
![]() |
a18c701866 | ||
![]() |
9871604a48 | ||
![]() |
b1d12fdc91 | ||
![]() |
24e717d532 | ||
![]() |
1568fedebd | ||
![]() |
c88578d537 | ||
![]() |
9827345213 | ||
![]() |
c51d14fb13 | ||
![]() |
480761c1f7 | ||
![]() |
12e909d9aa | ||
![]() |
b1e892487f | ||
![]() |
720eabcb16 | ||
![]() |
1fde71f3f4 | ||
![]() |
90f8b77171 | ||
![]() |
315d7521a7 | ||
![]() |
ff177b5eaf | ||
![]() |
46fd7e9a58 | ||
![]() |
edd274ccce | ||
![]() |
a5b2ec3006 | ||
![]() |
cd3c0d4fd7 | ||
![]() |
3bdd79a3fd | ||
![]() |
b04e01cda7 | ||
![]() |
bad5384c96 | ||
![]() |
443902f787 | ||
![]() |
d3cdd6959d | ||
![]() |
9762e15460 | ||
![]() |
33897e2c0f | ||
![]() |
9528e44b88 | ||
![]() |
03746e7606 | ||
![]() |
50eace16da | ||
![]() |
8241e46680 | ||
![]() |
160f64e9c2 | ||
![]() |
593c6c68ee | ||
![]() |
991753a492 | ||
![]() |
7cdd772f2b | ||
![]() |
c5f837fd19 | ||
![]() |
7c244d25b5 | ||
![]() |
18fc4d419f | ||
![]() |
813fa055a3 | ||
![]() |
6a47846b84 | ||
![]() |
b0041217b0 | ||
![]() |
fedcd28ecc | ||
![]() |
b17c6b9748 | ||
![]() |
204d379176 | ||
![]() |
a754ce9eb6 | ||
![]() |
99b5f46a9e | ||
![]() |
394d8c3bf6 | ||
![]() |
4bdbcf30ff | ||
![]() |
63de0fd33c | ||
![]() |
0fbb7c44bd | ||
![]() |
5092713876 | ||
![]() |
f369afed77 | ||
![]() |
f23f0edc70 | ||
![]() |
daee00da95 | ||
![]() |
e2cdac0406 | ||
![]() |
cc44ec99ba | ||
![]() |
1bf3b1ed37 | ||
![]() |
f7b530ebae | ||
![]() |
b185e2e792 | ||
![]() |
73ec2abd43 | ||
![]() |
cfee4c6bc1 | ||
![]() |
2d4b9c0d93 | ||
![]() |
f522d3697c | ||
![]() |
48e96b2f3b | ||
![]() |
798908f127 | ||
![]() |
7e3127549f | ||
![]() |
4713325877 | ||
![]() |
7cc6a3cab9 | ||
![]() |
cba5731576 | ||
![]() |
b3656c95f5 | ||
![]() |
e9539dfee2 | ||
![]() |
4b40812e26 | ||
![]() |
ef8cd1f591 | ||
![]() |
46cdb89921 | ||
![]() |
3094ff6e3b | ||
![]() |
4d42d6ff33 | ||
![]() |
a427d2c1a9 | ||
![]() |
efb7a8d453 | ||
![]() |
6c4872eae9 | ||
![]() |
ff639a267d | ||
![]() |
94e4b671f3 | ||
![]() |
096c8aab50 | ||
![]() |
89186a86c8 | ||
![]() |
c8c1c65e8c | ||
![]() |
c5e1d5fa20 | ||
![]() |
91011695f0 |
@@ -2,23 +2,43 @@ cmake_minimum_required(VERSION 2.6)
|
|||||||
|
|
||||||
project(chaiscript)
|
project(chaiscript)
|
||||||
|
|
||||||
SET (CMAKE_BUILD_TYPE gdb)
|
FIND_LIBRARY(READLINE_LIBRARY NAMES readline PATH /usr/lib /usr/local/lib /opt/local/lib)
|
||||||
SET (CMAKE_C_FLAGS_GDB " -Wall -ggdb")
|
|
||||||
SET (CMAKE_CXX_FLAGS_GDB " -Wall -ggdb")
|
|
||||||
|
|
||||||
#SET (CMAKE_BUILD_TYPE rel)
|
MESSAGE(STATUS "Detecting readline support")
|
||||||
#SET (CMAKE_C_FLAGS_REL " -Wall -O3")
|
if (READLINE_LIBRARY)
|
||||||
#SET (CMAKE_CXX_FLAGS_REL " -Wall -O3")
|
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)
|
include_directories(include)
|
||||||
|
|
||||||
find_package(Boost 1.36.0)
|
find_package(Boost 1.36.0 COMPONENTS thread)
|
||||||
|
|
||||||
if (Boost_FOUND)
|
if (Boost_FOUND)
|
||||||
include_directories(${Boost_INCLUDE_DIRS})
|
include_directories(${Boost_INCLUDE_DIRS})
|
||||||
add_executable(chaiscript_eval src/main.cpp)
|
add_executable(chaiscript_eval src/main.cpp)
|
||||||
#add_executable(dispatchkit_test contrib/test/dispatchkit_test.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)
|
install(TARGETS chaiscript_eval DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/bin)
|
||||||
|
|
||||||
else(Boost_FOUND)
|
else(Boost_FOUND)
|
||||||
message(FATAL_ERROR "Can not find Boost")
|
message(FATAL_ERROR "Can not find Boost")
|
||||||
endif(Boost_FOUND)
|
endif(Boost_FOUND)
|
||||||
|
43
contrib/codeanalysis/analyzedata.sh
Executable file
43
contrib/codeanalysis/analyzedata.sh
Executable 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
|
81
contrib/codeanalysis/codeanalysis.sh
Executable file
81
contrib/codeanalysis/codeanalysis.sh
Executable 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
|
15
contrib/codeanalysis/profile.chai
Normal file
15
contrib/codeanalysis/profile.chai
Normal 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)
|
@@ -21,114 +21,13 @@
|
|||||||
#include "dispatchkit/bootstrap.hpp"
|
#include "dispatchkit/bootstrap.hpp"
|
||||||
#include "dispatchkit/bootstrap_stl.hpp"
|
#include "dispatchkit/bootstrap_stl.hpp"
|
||||||
#include "dispatchkit/function_call.hpp"
|
#include "dispatchkit/function_call.hpp"
|
||||||
namespace chaiscript
|
#include "dispatchkit/dynamic_object.hpp"
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 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 }; };
|
|
||||||
|
|
||||||
/**
|
#ifdef BOOST_HAS_DECLSPEC
|
||||||
* Helper lookup to get the name of each node type
|
#define CHAISCRIPT_MODULE_EXPORT extern "C" __declspec(dllexport)
|
||||||
*/
|
#else
|
||||||
const char *token_type_to_string(int tokentype) {
|
#define CHAISCRIPT_MODULE_EXPORT extern "C"
|
||||||
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
#endif
|
||||||
"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 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) { }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "language/chaiscript_eval.hpp"
|
#include "language/chaiscript_eval.hpp"
|
||||||
#include "language/chaiscript_engine.hpp"
|
#include "language/chaiscript_engine.hpp"
|
||||||
|
73
include/chaiscript/chaiscript_threading.hpp
Normal file
73
include/chaiscript/chaiscript_threading.hpp
Normal 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
|
||||||
|
|
65
include/chaiscript/dispatchkit/bind_first.hpp
Normal file
65
include/chaiscript/dispatchkit/bind_first.hpp
Normal 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
|
@@ -8,6 +8,7 @@
|
|||||||
#define __bootstrap_hpp__
|
#define __bootstrap_hpp__
|
||||||
|
|
||||||
#include "dispatchkit.hpp"
|
#include "dispatchkit.hpp"
|
||||||
|
#include "dynamic_object.hpp"
|
||||||
#include "register_function.hpp"
|
#include "register_function.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
@@ -49,6 +50,18 @@ namespace chaiscript
|
|||||||
return p1 % p2;
|
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>
|
template<typename P1, typename P2>
|
||||||
P1 &assign(P1 &p1, const P2 &p2)
|
P1 &assign(P1 &p1, const P2 &p2)
|
||||||
{
|
{
|
||||||
@@ -482,18 +495,6 @@ namespace chaiscript
|
|||||||
return boost::lexical_cast<std::string>(i);
|
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
|
* Internal function for converting from a string to a value
|
||||||
@@ -532,22 +533,39 @@ namespace chaiscript
|
|||||||
* function variables.
|
* function variables.
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
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
|
* Assignment function for shared_ptr objects, does not perform a copy of the
|
||||||
* object pointed to, instead maintains the shared_ptr concept.
|
* object pointed to, instead maintains the shared_ptr concept.
|
||||||
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
* Similar to shared_ptr_clone. Used for Proxy_Function.
|
||||||
*/
|
*/
|
||||||
template<typename Type>
|
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));
|
if (lhs.is_unknown()
|
||||||
|
|| (!lhs.get_type_info().is_const() && lhs.get_type_info().bare_equal(chaiscript::detail::Get_Type_Info<Type>::get())))
|
||||||
return lhs;
|
{
|
||||||
|
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);
|
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()))));
|
std::vector<Boxed_Value>(params.begin() + 1, params.end()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,17 +651,39 @@ namespace chaiscript
|
|||||||
throw arity_error(params.size(), 1);
|
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())));
|
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()))
|
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");
|
e->add(user_type<void>(), "void");
|
||||||
return e;
|
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:
|
public:
|
||||||
/**
|
/**
|
||||||
* perform all common bootstrap functions for std::string, void and POD types
|
* 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_Value>(), "Object");
|
||||||
m->add(user_type<Boxed_POD_Value>(), "PODObject");
|
m->add(user_type<Boxed_POD_Value>(), "PODObject");
|
||||||
m->add(user_type<Proxy_Function>(), "function");
|
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);
|
basic_constructors<bool>("bool", m);
|
||||||
oper_assign<std::string>(m);
|
oper_assign<std::string>(m);
|
||||||
oper_assign<bool>(m);
|
oper_assign<bool>(m);
|
||||||
|
|
||||||
m->add(fun(&to_string<const std::string &>), "internal_to_string");
|
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(&unknown_assign), "=");
|
||||||
|
m->add(fun(&throw_exception), "throw");
|
||||||
|
m->add(fun(&what), "what");
|
||||||
|
|
||||||
bootstrap_pod_type<double>("double", m);
|
bootstrap_pod_type<double>("double", m);
|
||||||
bootstrap_pod_type<int>("int", m);
|
bootstrap_pod_type<int>("int", m);
|
||||||
@@ -674,6 +729,8 @@ namespace chaiscript
|
|||||||
opers_arithmetic_pod(m);
|
opers_arithmetic_pod(m);
|
||||||
|
|
||||||
m->add(fun(&detail::modulus<int, int, int>), "%");
|
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(&print), "print_string");
|
||||||
m->add(fun(&println), "println_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))),
|
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&bind_function, _1))),
|
||||||
"bind");
|
"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(fun(&ptr_assign<Proxy_Function_Base>), "=");
|
||||||
|
|
||||||
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
|
m->add(Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&call_exists, _1))),
|
||||||
|
@@ -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
|
bool empty() const
|
||||||
{
|
{
|
||||||
return m_begin == m_end;
|
return m_begin == m_end;
|
||||||
@@ -118,20 +108,10 @@ namespace chaiscript
|
|||||||
ModulePtr input_range_type(const std::string &type, ModulePtr m = ModulePtr(new Module()))
|
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<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<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> (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>::empty), "empty");
|
||||||
m->add(fun(&Bidir_Range<ContainerType>::pop_front), "pop_front");
|
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>::pop_back), "pop_back");
|
||||||
m->add(fun(&Bidir_Range<ContainerType>::back), "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;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,9 +145,7 @@ namespace chaiscript
|
|||||||
//In the interest of runtime safety for the m, we prefer the at() method for [] access,
|
//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.
|
//to throw an exception in an out of bounds condition.
|
||||||
m->add(
|
m->add(
|
||||||
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::at))), "[]");
|
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(static_cast<indexoper>(&ContainerType::at))), "[]");
|
||||||
m->add(
|
|
||||||
fun(boost::function<typename ContainerType::reference (ContainerType *, int)>(indexoper(&ContainerType::operator[]))), "at");
|
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -204,7 +172,6 @@ namespace chaiscript
|
|||||||
assignable_type<ContainerType>(type, m);
|
assignable_type<ContainerType>(type, m);
|
||||||
|
|
||||||
m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::size), "size");
|
m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::size), "size");
|
||||||
m->add(fun<size_t (ContainerType::*)() const>(&ContainerType::max_size), "max_size");
|
|
||||||
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
|
m->add(fun<bool (ContainerType::*)() const>(&ContainerType::empty), "empty");
|
||||||
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
|
m->add(fun<void (ContainerType::*)()>(&ContainerType::clear), "clear");
|
||||||
|
|
||||||
@@ -307,7 +274,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
typedef typename ContainerType::reference (ContainerType::*backptr)();
|
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;
|
std::string push_back_name;
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value))
|
||||||
@@ -322,6 +289,45 @@ namespace chaiscript
|
|||||||
return m;
|
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
|
* Create a vector type with associated concepts
|
||||||
* http://www.sgi.com/tech/stl/Vector.html
|
* http://www.sgi.com/tech/stl/Vector.html
|
||||||
@@ -404,7 +410,6 @@ namespace chaiscript
|
|||||||
|
|
||||||
reversible_container_type<ContainerType>(type, m);
|
reversible_container_type<ContainerType>(type, m);
|
||||||
associative_container_type<ContainerType>(type, m);
|
associative_container_type<ContainerType>(type, m);
|
||||||
m->add(fun(eq_range(&ContainerType::equal_range)), "equal_range");
|
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
@@ -462,12 +467,12 @@ namespace chaiscript
|
|||||||
m->add(fun(&String::push_back), push_back_name);
|
m->add(fun(&String::push_back), push_back_name);
|
||||||
|
|
||||||
typedef typename String::size_type (String::*find_func)(const String &, typename String::size_type) const;
|
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(static_cast<find_func>(&String::find)), "find");
|
||||||
m->add(fun(find_func(&String::rfind)), "rfind");
|
m->add(fun(static_cast<find_func>(&String::rfind)), "rfind");
|
||||||
m->add(fun(find_func(&String::find_first_of)), "find_first_of");
|
m->add(fun(static_cast<find_func>(&String::find_first_of)), "find_first_of");
|
||||||
m->add(fun(find_func(&String::find_last_of)), "find_last_of");
|
m->add(fun(static_cast<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(static_cast<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_last_not_of)), "find_last_not_of");
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#define __boxed_value_hpp__
|
#define __boxed_value_hpp__
|
||||||
|
|
||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
|
#include "../chaiscript_threading.hpp"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/any.hpp>
|
#include <boost/any.hpp>
|
||||||
@@ -134,6 +135,8 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
boost::shared_ptr<Data> get(const boost::shared_ptr<T> &obj)
|
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(
|
boost::shared_ptr<Data> data(new Data(
|
||||||
detail::Get_Type_Info<T>::get(),
|
detail::Get_Type_Info<T>::get(),
|
||||||
boost::any(obj),
|
boost::any(obj),
|
||||||
@@ -141,14 +144,14 @@ namespace chaiscript
|
|||||||
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
|
boost::shared_ptr<Data::Shared_Ptr_Proxy>(new Data::Shared_Ptr_Proxy_Impl<T>()))
|
||||||
);
|
);
|
||||||
|
|
||||||
std::map<const void *, Data>::iterator itr
|
std::map<std::pair<const void *, bool>, Data>::iterator itr
|
||||||
= m_ptrs.find(obj.get());
|
= m_ptrs.find(std::make_pair(obj.get(), b_const));
|
||||||
|
|
||||||
if (itr != m_ptrs.end())
|
if (itr != m_ptrs.end())
|
||||||
{
|
{
|
||||||
(*data) = (itr->second);
|
(*data) = (itr->second);
|
||||||
} else {
|
} 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;
|
return data;
|
||||||
@@ -163,14 +166,16 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
boost::shared_ptr<Data> get(boost::reference_wrapper<T> obj)
|
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(
|
boost::shared_ptr<Data> data(new Data(
|
||||||
detail::Get_Type_Info<T>::get(),
|
detail::Get_Type_Info<T>::get(),
|
||||||
boost::any(obj),
|
boost::any(obj),
|
||||||
true)
|
true)
|
||||||
);
|
);
|
||||||
|
|
||||||
std::map<const void *, Data >::iterator itr
|
std::map<std::pair<const void *, bool>, Data >::iterator itr
|
||||||
= m_ptrs.find(obj.get_pointer());
|
= 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,
|
// 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
|
// 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
|
// Both t and t.x share the same memory location, but do not represent
|
||||||
// objects of the same type.
|
// objects of the same type.
|
||||||
if (itr != m_ptrs.end()
|
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);
|
(*data) = (itr->second);
|
||||||
}
|
}
|
||||||
@@ -200,7 +205,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
boost::shared_ptr<T> *ptr = boost::any_cast<boost::shared_ptr<T> >(&data->m_obj);
|
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;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,21 +222,23 @@ namespace chaiscript
|
|||||||
* Drop objects from the cache where there is only one (ie, our)
|
* Drop objects from the cache where there is only one (ie, our)
|
||||||
* reference to it, so it may be destructed
|
* reference to it, so it may be destructed
|
||||||
*/
|
*/
|
||||||
void cull()
|
void cull(bool force = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
++m_cullcount;
|
++m_cullcount;
|
||||||
if (m_cullcount % 10 != 0)
|
if (force || m_cullcount % 10 != 0)
|
||||||
{
|
{
|
||||||
return;
|
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())
|
while (itr != m_ptrs.end())
|
||||||
{
|
{
|
||||||
if (itr->second.m_ptr_proxy->unique(&itr->second.m_obj) == 1)
|
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;
|
++itr;
|
||||||
m_ptrs.erase(todel);
|
m_ptrs.erase(todel);
|
||||||
} else {
|
} 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;
|
int m_cullcount;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -278,10 +285,15 @@ namespace chaiscript
|
|||||||
/**
|
/**
|
||||||
* Return a reference to the static global Object_Cache
|
* Return a reference to the static global Object_Cache
|
||||||
*/
|
*/
|
||||||
Object_Cache &get_object_cache()
|
static Object_Cache &get_object_cache()
|
||||||
{
|
{
|
||||||
static Object_Cache oc;
|
static chaiscript::threading::Thread_Storage<Object_Cache> oc;
|
||||||
return oc;
|
return *oc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clear_cache()
|
||||||
|
{
|
||||||
|
get_object_cache().m_ptrs.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -313,7 +325,7 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
bool is_unknown() const
|
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
|
boost::any get() const
|
||||||
@@ -347,14 +359,19 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
if (ob.is_ref())
|
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());
|
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
|
||||||
} else {
|
} else {
|
||||||
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
||||||
}
|
}
|
||||||
} else {
|
} 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.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());
|
return boost::cref((boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get());
|
||||||
} else {
|
} else {
|
||||||
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
return boost::any_cast<boost::reference_wrapper<const Result> >(ob.get());
|
||||||
}
|
}
|
||||||
} else {
|
} 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.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();
|
return (boost::any_cast<boost::reference_wrapper<Result> >(ob.get())).get_pointer();
|
||||||
} else {
|
} else {
|
||||||
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
|
return (boost::any_cast<boost::reference_wrapper<const Result> >(ob.get())).get_pointer();
|
||||||
}
|
}
|
||||||
} else {
|
} 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>
|
template<typename Result>
|
||||||
struct Cast_Helper<const boost::shared_ptr<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:
|
public:
|
||||||
bad_boxed_cast(const Type_Info &t_from, const std::type_info &t_to) throw()
|
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();
|
return m_what.c_str();
|
||||||
}
|
}
|
||||||
const std::type_info *from;
|
|
||||||
|
Type_Info from;
|
||||||
const std::type_info *to;
|
const std::type_info *to;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -558,12 +624,12 @@ namespace chaiscript
|
|||||||
Boxed_POD_Value(const Boxed_Value &v)
|
Boxed_POD_Value(const Boxed_Value &v)
|
||||||
: d(0), i(0), m_isfloat(false)
|
: 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();
|
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))
|
if (inp_ == typeid(double))
|
||||||
{
|
{
|
||||||
@@ -702,6 +768,30 @@ namespace chaiscript
|
|||||||
return Boxed_Value(t);
|
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
|
* Return true if the two Boxed_Values share the same internal type
|
||||||
*/
|
*/
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
#include <boost/tuple/tuple.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -22,6 +23,8 @@
|
|||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
#include "proxy_functions.hpp"
|
#include "proxy_functions.hpp"
|
||||||
#include "proxy_constructors.hpp"
|
#include "proxy_constructors.hpp"
|
||||||
|
#include "dynamic_object.hpp"
|
||||||
|
#include "../chaiscript_threading.hpp"
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
{
|
{
|
||||||
@@ -40,16 +43,26 @@ namespace chaiscript
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
//Add a bit of chaiscript to eval during module implementation
|
||||||
void apply(T &t) const
|
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_typeinfos.begin(), m_typeinfos.end(), t_engine);
|
||||||
apply(m_funcs.begin(), m_funcs.end(), t);
|
apply(m_funcs.begin(), m_funcs.end(), t_engine);
|
||||||
|
apply_eval(m_evals.begin(), m_evals.end(), t_eval);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
|
std::vector<std::pair<Type_Info, std::string> > m_typeinfos;
|
||||||
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
|
std::vector<std::pair<Proxy_Function, std::string> > m_funcs;
|
||||||
|
std::vector<std::string> m_evals;
|
||||||
|
|
||||||
template<typename T, typename InItr>
|
template<typename T, typename InItr>
|
||||||
void apply(InItr begin, InItr end, T &t) const
|
void apply(InItr begin, InItr end, T &t) const
|
||||||
@@ -60,6 +73,18 @@ namespace chaiscript
|
|||||||
++begin;
|
++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;
|
typedef boost::shared_ptr<Module> ModulePtr;
|
||||||
@@ -73,7 +98,8 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Dispatch_Function(const std::vector<std::pair<std::string, Proxy_Function > > &t_funcs)
|
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 ~Dispatch_Function() {}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return dispatch(m_funcs, params);
|
return dispatch(m_funcs.begin(), m_funcs.end(), params);
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::vector<Type_Info> get_param_types() const
|
|
||||||
{
|
|
||||||
return std::vector<Type_Info>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int get_arity() const
|
virtual int get_arity() const
|
||||||
@@ -155,13 +176,19 @@ namespace chaiscript
|
|||||||
public:
|
public:
|
||||||
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
typedef std::map<std::string, chaiscript::Type_Info> Type_Name_Map;
|
||||||
typedef std::map<std::string, Boxed_Value> Scope;
|
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()
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,15 +197,10 @@ namespace chaiscript
|
|||||||
bool add(const Proxy_Function &f, const std::string &name)
|
bool add(const Proxy_Function &f, const std::string &name)
|
||||||
{
|
{
|
||||||
validate_object_name(name);
|
validate_object_name(name);
|
||||||
return add_function(f, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
StackData &stack = get_stack_data();
|
||||||
* Add a module's worth of registrations to the system
|
stack.get<0>().erase(name);
|
||||||
*/
|
return add_function(f, name);
|
||||||
void add(const ModulePtr &m)
|
|
||||||
{
|
|
||||||
m->apply(*this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -188,12 +210,15 @@ namespace chaiscript
|
|||||||
void add(const Boxed_Value &obj, const std::string &name)
|
void add(const Boxed_Value &obj, const std::string &name)
|
||||||
{
|
{
|
||||||
validate_object_name(name);
|
validate_object_name(name);
|
||||||
for (int i = m_scopes->size()-1; i >= 0; --i)
|
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);
|
std::map<std::string, Boxed_Value>::const_iterator itr = (stack.get<1>())[i].find(name);
|
||||||
if (itr != (*m_scopes)[i].end())
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,8 +231,26 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
void add_object(const std::string &name, const Boxed_Value &obj)
|
void add_object(const std::string &name, const Boxed_Value &obj)
|
||||||
{
|
{
|
||||||
|
StackData &stack = get_stack_data();
|
||||||
validate_object_name(name);
|
validate_object_name(name);
|
||||||
m_scopes->back()[name] = Boxed_Value(obj);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,7 +258,8 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
void new_scope()
|
void new_scope()
|
||||||
{
|
{
|
||||||
m_scopes->push_back(Scope());
|
StackData &stack = get_stack_data();
|
||||||
|
stack.get<1>().push_back(Scope());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,22 +267,22 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
void pop_scope()
|
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 {
|
} else {
|
||||||
throw std::range_error("Unable to pop global stack");
|
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
|
* Swaps out the stack with a new stack
|
||||||
* \returns the old stack
|
* \returns the old stack
|
||||||
@@ -246,14 +290,33 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
Stack set_stack(const Stack &s)
|
Stack set_stack(const Stack &s)
|
||||||
{
|
{
|
||||||
Stack old = m_scopes;
|
Stack old = m_stack_holder->stack;
|
||||||
m_scopes = s;
|
m_stack_holder->stack = s;
|
||||||
return old;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -263,27 +326,58 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
Boxed_Value get_object(const std::string &name) const
|
Boxed_Value get_object(const std::string &name) const
|
||||||
{
|
{
|
||||||
|
// Is it a placeholder object?
|
||||||
if (name == "_")
|
if (name == "_")
|
||||||
{
|
{
|
||||||
return m_place_holder;
|
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);
|
return itr->second;
|
||||||
if (itr != (*m_scopes)[i].end())
|
}
|
||||||
|
|
||||||
|
// 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;
|
return itr->second;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> > funcs = get_function(name);
|
||||||
|
|
||||||
if (funcs.empty())
|
if (funcs.empty())
|
||||||
{
|
{
|
||||||
throw std::range_error("Object not known: " + name);
|
throw std::range_error("Object not known: " + name);
|
||||||
} else {
|
} 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,6 +386,10 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
void add(const Type_Info &ti, const std::string &name)
|
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));
|
m_types.insert(std::make_pair(name, ti));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +398,10 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
Type_Info get_type(const std::string &name) const
|
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);
|
Type_Name_Map::const_iterator itr = m_types.find(name);
|
||||||
|
|
||||||
if (itr != m_types.end())
|
if (itr != m_types.end())
|
||||||
@@ -317,17 +419,21 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
std::string get_type_name(const Type_Info &ti) const
|
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();
|
for (Type_Name_Map::const_iterator itr = m_types.begin();
|
||||||
itr != m_types.end();
|
itr != m_types.end();
|
||||||
++itr)
|
++itr)
|
||||||
{
|
{
|
||||||
if (itr->second.m_bare_type_info == ti.m_bare_type_info)
|
if (itr->second.bare_equal(ti))
|
||||||
{
|
{
|
||||||
return itr->first;
|
return itr->first;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ti.m_bare_type_info->name();
|
return ti.bare_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -335,17 +441,21 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
std::vector<std::pair<std::string, Type_Info> > get_types() const
|
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());
|
return std::vector<std::pair<std::string, Type_Info> >(m_types.begin(), m_types.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a function by name
|
* Return a function by name
|
||||||
*/
|
*/
|
||||||
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
|
std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >
|
||||||
get_function(const std::string &t_name) const
|
get_function(const std::string &t_name) const
|
||||||
{
|
{
|
||||||
std::pair<std::multimap<std::string, Proxy_Function >::const_iterator, std::multimap<std::string, Proxy_Function >::const_iterator> range
|
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);
|
= 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 std::vector<std::pair<std::string, std::multimap<std::string, Proxy_Function >::mapped_type> >(range.first, range.second);
|
||||||
}
|
}
|
||||||
@@ -355,7 +465,8 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
bool function_exists(const std::string &name) const
|
bool function_exists(const std::string &name) const
|
||||||
{
|
{
|
||||||
return m_functions.find(name) != m_functions.end();
|
std::multimap<std::string, Proxy_Function> &functions = get_function_cache();
|
||||||
|
return functions.find(name) != functions.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -363,21 +474,157 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
std::vector<std::pair<std::string, Proxy_Function > > get_functions() const
|
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)
|
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);
|
m_reserved_words.insert(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Boxed_Value call_function(const std::string &t_name, const std::vector<Boxed_Value> ¶ms) 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:
|
private:
|
||||||
|
/**
|
||||||
|
* Returns the current stack
|
||||||
|
* make const/non const versions
|
||||||
|
*/
|
||||||
|
StackData &get_stack_data() const
|
||||||
|
{
|
||||||
|
return *(m_stack_holder->stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
* Throw a reserved_word exception if the name is not allowed
|
||||||
*/
|
*/
|
||||||
void validate_object_name(const std::string &name)
|
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())
|
if (m_reserved_words.find(name) != m_reserved_words.end())
|
||||||
{
|
{
|
||||||
throw reserved_word_error(name);
|
throw reserved_word_error(name);
|
||||||
@@ -391,6 +638,10 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
bool add_function(const Proxy_Function &f, const std::string &t_name)
|
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
|
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);
|
= m_functions.equal_range(t_name);
|
||||||
|
|
||||||
@@ -404,110 +655,41 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_functions.insert(std::make_pair(t_name, f));
|
m_functions.insert(std::make_pair(t_name, f));
|
||||||
|
get_function_cache().insert(std::make_pair(t_name, f));
|
||||||
|
|
||||||
return true;
|
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;
|
Type_Name_Map m_types;
|
||||||
Boxed_Value m_place_holder;
|
Boxed_Value m_place_holder;
|
||||||
|
|
||||||
std::set<std::string> m_reserved_words;
|
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
|
#endif
|
||||||
|
226
include/chaiscript/dispatchkit/dynamic_object.hpp
Normal file
226
include/chaiscript/dispatchkit/dynamic_object.hpp
Normal 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> ¶ms) 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> ¶ms) 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
|
||||||
|
|
@@ -23,27 +23,27 @@ namespace chaiscript
|
|||||||
template<typename Ret>
|
template<typename Ret>
|
||||||
struct Handle_Return
|
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>
|
template<typename Ret>
|
||||||
struct Handle_Return<boost::shared_ptr<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>
|
template<typename Ret>
|
||||||
struct Handle_Return<const boost::shared_ptr<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>
|
template<typename Ret>
|
||||||
struct Handle_Return<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<>
|
template<>
|
||||||
struct Handle_Return<Boxed_Value>
|
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<>
|
template<>
|
||||||
struct Handle_Return<Boxed_Value &>
|
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<>
|
template<>
|
||||||
struct Handle_Return<void>
|
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());
|
return Boxed_Value(Boxed_Value::Void_Type());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include "type_info.hpp"
|
#include "type_info.hpp"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "proxy_functions_detail.hpp"
|
#include "proxy_functions_detail.hpp"
|
||||||
@@ -63,8 +62,10 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Proxy_Function_Base() {}
|
virtual ~Proxy_Function_Base() {}
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) = 0;
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const = 0;
|
||||||
virtual std::vector<Type_Info> get_param_types() const = 0;
|
|
||||||
|
std::vector<Type_Info> get_param_types() const { return m_types; }
|
||||||
|
|
||||||
virtual bool operator==(const Proxy_Function_Base &) const = 0;
|
virtual bool operator==(const Proxy_Function_Base &) const = 0;
|
||||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) 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];
|
const Type_Info &ti = types[1];
|
||||||
|
|
||||||
if (!ti.m_bare_type_info || !(vals[0].get_type_info().m_bare_type_info)
|
if (ti.is_unknown() || vals[0].get_type_info().is_unknown()
|
||||||
|| (*ti.m_bare_type_info) == (*user_type<Boxed_Value>().m_bare_type_info)
|
|| ti.bare_equal(user_type<Boxed_Value>())
|
||||||
|| (*ti.m_bare_type_info) == (*user_type<Boxed_POD_Value>().m_bare_type_info)
|
|| ti.bare_equal(user_type<Boxed_POD_Value>())
|
||||||
|| (*vals[0].get_type_info().m_bare_type_info) == (*ti.m_bare_type_info))
|
|| ti.bare_equal(vals[0].get_type_info()))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -109,9 +110,36 @@ namespace chaiscript
|
|||||||
virtual int get_arity() const = 0;
|
virtual int get_arity() const = 0;
|
||||||
|
|
||||||
virtual std::string annotation() 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<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
|
* Exception thrown if a function's guard fails to execute
|
||||||
@@ -139,8 +167,8 @@ namespace chaiscript
|
|||||||
int t_arity=-1,
|
int t_arity=-1,
|
||||||
const std::string &t_description = "",
|
const std::string &t_description = "",
|
||||||
const Proxy_Function &t_guard = Proxy_Function())
|
const Proxy_Function &t_guard = Proxy_Function())
|
||||||
: m_f(t_f), m_arity(t_arity), m_description(t_description), m_guard(t_guard),
|
: Proxy_Function_Base(build_param_type_list(t_arity)),
|
||||||
m_types(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 ~Dynamic_Proxy_Function() {}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||||
{
|
{
|
||||||
@@ -179,11 +207,6 @@ namespace chaiscript
|
|||||||
return m_arity;
|
return m_arity;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Type_Info> get_param_types() const
|
|
||||||
{
|
|
||||||
return m_types;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string annotation() const
|
virtual std::string annotation() const
|
||||||
{
|
{
|
||||||
return m_description;
|
return m_description;
|
||||||
@@ -229,7 +252,6 @@ namespace chaiscript
|
|||||||
int m_arity;
|
int m_arity;
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
Proxy_Function m_guard;
|
Proxy_Function m_guard;
|
||||||
std::vector<Type_Info> m_types;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -249,9 +271,10 @@ namespace chaiscript
|
|||||||
class Bound_Function : public Proxy_Function_Base
|
class Bound_Function : public Proxy_Function_Base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Bound_Function(const Proxy_Function &t_f,
|
Bound_Function(const Const_Proxy_Function &t_f,
|
||||||
const std::vector<Boxed_Value> &t_args)
|
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));
|
return m_f->call_match(build_param_list(vals));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return (*m_f)(build_param_list(params));
|
return (*m_f)(build_param_list(params));
|
||||||
}
|
}
|
||||||
@@ -310,11 +333,6 @@ namespace chaiscript
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<Type_Info> get_param_types() const
|
|
||||||
{
|
|
||||||
return std::vector<Type_Info>();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual int get_arity() const
|
virtual int get_arity() const
|
||||||
{
|
{
|
||||||
return m_arity;
|
return m_arity;
|
||||||
@@ -326,7 +344,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Proxy_Function m_f;
|
Const_Proxy_Function m_f;
|
||||||
std::vector<Boxed_Value> m_args;
|
std::vector<Boxed_Value> m_args;
|
||||||
int m_arity;
|
int m_arity;
|
||||||
};
|
};
|
||||||
@@ -341,7 +359,8 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Proxy_Function_Impl(const boost::function<Func> &f)
|
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> ¶ms)
|
virtual Boxed_Value operator()(const std::vector<Boxed_Value> ¶ms) const
|
||||||
{
|
{
|
||||||
return call_func(m_f, params);
|
return Do_Call<typename boost::function<Func>::result_type>::go(m_f, params);
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::vector<Type_Info> get_param_types() const
|
|
||||||
{
|
|
||||||
return m_types;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int get_arity() const
|
virtual int get_arity() const
|
||||||
@@ -375,7 +389,12 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual bool call_match(const std::vector<Boxed_Value> &vals) const
|
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
|
virtual std::string annotation() const
|
||||||
@@ -386,7 +405,6 @@ namespace chaiscript
|
|||||||
private:
|
private:
|
||||||
boost::function<Func> m_f;
|
boost::function<Func> m_f;
|
||||||
Func *m_dummy_func;
|
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
|
* 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
|
* 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)
|
const std::vector<Boxed_Value> &plist)
|
||||||
{
|
{
|
||||||
for (std::vector<std::pair<std::string, Proxy_Function> >::const_iterator itr = funcs.begin();
|
while (begin != end)
|
||||||
itr != funcs.end();
|
|
||||||
++itr)
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (itr->second->filter(plist))
|
if (begin->second->filter(plist))
|
||||||
{
|
{
|
||||||
return (*itr->second)(plist);
|
return (*begin->second)(plist);
|
||||||
}
|
}
|
||||||
} catch (const bad_boxed_cast &) {
|
} catch (const bad_boxed_cast &) {
|
||||||
//parameter failed to cast, try again
|
//parameter failed to cast, try again
|
||||||
@@ -430,9 +447,23 @@ namespace chaiscript
|
|||||||
//guard failed to allow the function to execute,
|
//guard failed to allow the function to execute,
|
||||||
//try again
|
//try again
|
||||||
}
|
}
|
||||||
|
++begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw dispatch_error();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -7,11 +7,9 @@
|
|||||||
#include <boost/preprocessor.hpp>
|
#include <boost/preprocessor.hpp>
|
||||||
|
|
||||||
#define gettypeinfo(z,n,text) ti.push_back(detail::Get_Type_Info<Param ## n>::get());
|
#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 casthelper(z,n,text) BOOST_PP_COMMA_IF(n) 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 trycast(z,n,text) 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 BOOST_PP_IS_ITERATING
|
||||||
#ifndef __proxy_functions_detail_hpp__
|
#ifndef __proxy_functions_detail_hpp__
|
||||||
#define __proxy_functions_detail_hpp__
|
#define __proxy_functions_detail_hpp__
|
||||||
@@ -45,6 +43,27 @@ namespace chaiscript
|
|||||||
int got;
|
int got;
|
||||||
int expected;
|
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> ¶ms)
|
||||||
|
{
|
||||||
|
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> ¶ms)
|
||||||
|
{
|
||||||
|
call_func(fun, params);
|
||||||
|
return Handle_Return<void>::handle();
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
|
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
|
||||||
@@ -80,14 +99,14 @@ namespace chaiscript
|
|||||||
* the bad_boxed_cast is passed up to the caller.
|
* 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)>
|
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> ¶ms)
|
const std::vector<Boxed_Value> ¶ms)
|
||||||
{
|
{
|
||||||
if (params.size() != n)
|
if (params.size() != n)
|
||||||
{
|
{
|
||||||
throw arity_error(params.size(), n);
|
throw arity_error(params.size(), n);
|
||||||
} else {
|
} 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
|
* registration of two functions with the exact same signatures
|
||||||
*/
|
*/
|
||||||
template<typename Ret BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename Param)>
|
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)),
|
bool compare_types_cast(Ret (*)(BOOST_PP_ENUM_PARAMS(n, Param)),
|
||||||
const std::vector<Boxed_Value> ¶ms)
|
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;
|
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
|
#endif
|
||||||
|
@@ -4,15 +4,15 @@
|
|||||||
// and Jason Turner (lefticus@gmail.com)
|
// and Jason Turner (lefticus@gmail.com)
|
||||||
// http://www.chaiscript.com
|
// http://www.chaiscript.com
|
||||||
|
|
||||||
#include <boost/preprocessor.hpp>
|
|
||||||
|
|
||||||
#ifndef BOOST_PP_IS_ITERATING
|
|
||||||
#ifndef __register_function_hpp__
|
#ifndef __register_function_hpp__
|
||||||
#define __register_function_hpp__
|
#define __register_function_hpp__
|
||||||
|
|
||||||
#include "dispatchkit.hpp"
|
#include "dispatchkit.hpp"
|
||||||
|
#include "bind_first.hpp"
|
||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
|
#include <boost/function_types/components.hpp>
|
||||||
|
#include <boost/function_types/function_type.hpp>
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
{
|
{
|
||||||
@@ -28,75 +28,63 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function fun_helper(const boost::function<T> &f)
|
boost::function<T> mk_boost_fun(const boost::function<T> &f)
|
||||||
{
|
{
|
||||||
return Proxy_Function(new Proxy_Function_Impl<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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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>
|
template<typename T, typename Class>
|
||||||
Proxy_Function fun_helper(T Class::* m)
|
Proxy_Function fun_helper(T Class::* m)
|
||||||
{
|
{
|
||||||
return fun_helper(boost::function<T& (Class *)>(boost::bind(&detail::get_member<T, Class>, m, _1)));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#define BOOST_PP_ITERATION_LIMITS ( 0, 10 )
|
template<typename T>
|
||||||
#define BOOST_PP_FILENAME_1 <chaiscript/dispatchkit/register_function.hpp>
|
Proxy_Function fun(const boost::function<T> &f)
|
||||||
#include BOOST_PP_ITERATE()
|
{
|
||||||
|
return detail::fun_helper(f);
|
||||||
|
}
|
||||||
|
|
||||||
namespace chaiscript
|
|
||||||
{
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function fun(T t)
|
Proxy_Function fun(T t)
|
||||||
{
|
{
|
||||||
return detail::fun_helper(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));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define n BOOST_PP_ITERATION()
|
|
||||||
|
|
||||||
namespace chaiscript
|
|
||||||
{
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 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_helper(Ret (*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
|
|
||||||
{
|
|
||||||
return fun_helper(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_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param)))
|
|
||||||
{
|
|
||||||
return fun_helper(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_helper(Ret (Class::*f)(BOOST_PP_ENUM_PARAMS(n, Param))const)
|
|
||||||
{
|
|
||||||
return fun_helper(boost::function<Ret (const Class* BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Param))>(f));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -21,60 +21,91 @@ namespace chaiscript
|
|||||||
/**
|
/**
|
||||||
* compile time deduced information about a type
|
* 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,
|
public:
|
||||||
const std::type_info *t_ti, const std::type_info *t_bareti)
|
Type_Info(bool t_is_const, bool t_is_reference, bool t_is_pointer, bool t_is_void,
|
||||||
: m_is_const(t_is_const), m_is_reference(t_is_reference), m_is_pointer(t_is_pointer),
|
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_is_void(t_is_void),
|
||||||
m_type_info(t_ti), m_bare_type_info(t_bareti),
|
m_type_info(t_ti), m_bare_type_info(t_bareti),
|
||||||
m_is_unknown(false)
|
m_is_unknown(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info()
|
Type_Info()
|
||||||
: m_is_const(false), m_is_reference(false), m_is_pointer(false),
|
: 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_void(false), m_type_info(0), m_bare_type_info(0),
|
||||||
m_is_unknown(true)
|
m_is_unknown(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Type_Info(const Type_Info &ti)
|
Type_Info(const Type_Info &ti)
|
||||||
: m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
|
: m_is_const(ti.m_is_const), m_is_reference(ti.m_is_reference),
|
||||||
m_is_pointer(ti.m_is_pointer),
|
m_is_pointer(ti.m_is_pointer),
|
||||||
m_is_void(ti.m_is_void), m_type_info(ti.m_type_info),
|
m_is_void(ti.m_is_void), m_type_info(ti.m_type_info),
|
||||||
m_bare_type_info(ti.m_bare_type_info),
|
m_bare_type_info(ti.m_bare_type_info),
|
||||||
m_is_unknown(ti.m_is_unknown)
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Type_Info &ti) const
|
Type_Info &operator=(const Type_Info &ti)
|
||||||
{
|
{
|
||||||
return ti.m_type_info == m_type_info;
|
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 operator<(const Type_Info &ti) const
|
||||||
bool m_is_reference;
|
{
|
||||||
bool m_is_pointer;
|
return m_type_info < ti.m_type_info;
|
||||||
bool m_is_void;
|
}
|
||||||
const std::type_info *m_type_info;
|
|
||||||
const std::type_info *m_bare_type_info;
|
bool operator==(const Type_Info &ti) const
|
||||||
bool m_is_unknown;
|
{
|
||||||
|
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
|
namespace detail
|
||||||
@@ -144,7 +175,6 @@ namespace chaiscript
|
|||||||
return detail::Get_Type_Info<T>::get();
|
return detail::Get_Type_Info<T>::get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
135
include/chaiscript/language/chaiscript_common.hpp
Normal file
135
include/chaiscript/language/chaiscript_common.hpp
Normal 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 */
|
||||||
|
|
@@ -10,42 +10,288 @@
|
|||||||
#include <exception>
|
#include <exception>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <chaiscript/language/chaiscript_common.hpp>
|
||||||
|
|
||||||
#include "chaiscript_prelude.hpp"
|
#ifdef _POSIX_VERSION
|
||||||
#include "chaiscript_parser.hpp"
|
#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
|
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>
|
template <typename Eval_Engine>
|
||||||
class ChaiScript_System {
|
class ChaiScript_System {
|
||||||
Eval_Engine engine;
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
|
mutable boost::shared_mutex mutex;
|
||||||
|
mutable boost::recursive_mutex use_mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
std::set<std::string> loaded_files;
|
std::set<std::string> loaded_files;
|
||||||
|
std::map<std::string, Loadable_Module_Ptr> loaded_modules;
|
||||||
|
|
||||||
ChaiScript_Parser parser;
|
Eval_Engine engine;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the given string in by parsing it and running the results through the evaluator
|
* Evaluates the given string in by parsing it and running the results through the evaluator
|
||||||
*/
|
*/
|
||||||
Boxed_Value do_eval(const std::string &input, const std::string &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);
|
//debug_print(tokens);
|
||||||
Boxed_Value value;
|
Boxed_Value value;
|
||||||
parser.clear_match_stack();
|
|
||||||
|
|
||||||
// Keep a cache of all loaded filenames and use the char * from this cache to pass
|
// 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
|
// to the parser. This is so that the parser does not have the overhead of passing
|
||||||
// around and copying strings
|
// around and copying strings
|
||||||
loaded_files.insert(filename);
|
//
|
||||||
|
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
|
||||||
|
|
||||||
try {
|
if (parser.parse(input, fname)) {
|
||||||
if (parser.parse(input, loaded_files.find(filename)->c_str())) {
|
//parser.show_match_stack();
|
||||||
//parser.show_match_stack();
|
value = eval_token<Eval_Engine>(engine, parser.ast());
|
||||||
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;
|
return value;
|
||||||
@@ -54,24 +300,45 @@ namespace chaiscript
|
|||||||
/**
|
/**
|
||||||
* Evaluates the given boxed string, used during eval() inside of a script
|
* Evaluates the given boxed string, used during eval() inside of a script
|
||||||
*/
|
*/
|
||||||
const Boxed_Value internal_eval(const std::vector<Boxed_Value> &vals) {
|
const Boxed_Value internal_eval(const std::string &e) {
|
||||||
return do_eval(boxed_cast<std::string>(vals.at(0)));
|
return do_eval(e, "__EVAL__", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void use(const std::string &filename)
|
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)
|
if (loaded_files.count(filename) == 0)
|
||||||
{
|
{
|
||||||
|
#ifndef CHAISCRIPT_NO_THREADS
|
||||||
|
l2.unlock();
|
||||||
|
#endif
|
||||||
eval_file(filename);
|
eval_file(filename);
|
||||||
|
} else {
|
||||||
|
engine.sync_cache();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ChaiScript_System() {
|
ChaiScript_System() {
|
||||||
|
loaded_files.insert("__EVAL__"); // Make sure the default name is already registered
|
||||||
build_eval_system();
|
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
|
* Adds an object to the system: type, function, object
|
||||||
*/
|
*/
|
||||||
@@ -87,11 +354,61 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
ChaiScript_System &add(const ModulePtr &p)
|
ChaiScript_System &add(const ModulePtr &p)
|
||||||
{
|
{
|
||||||
engine.add(p);
|
p->apply(*this, this->get_eval_engine());
|
||||||
|
|
||||||
return *this;
|
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
|
* Helper for calling script code as if it were native C++ code
|
||||||
* example:
|
* example:
|
||||||
@@ -174,28 +491,30 @@ namespace chaiscript
|
|||||||
engine.add_reserved_word("false");
|
engine.add_reserved_word("false");
|
||||||
engine.add_reserved_word("_");
|
engine.add_reserved_word("_");
|
||||||
|
|
||||||
|
add(Bootstrap::bootstrap());
|
||||||
|
|
||||||
engine.add(Bootstrap::bootstrap());
|
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(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");
|
|
||||||
|
|
||||||
engine.add(fun(boost::function<std::string (Boxed_Value)>(boost::bind(&chaiscript::type_name, boost::ref(engine), _1))),
|
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_1)(const std::string&);
|
||||||
"type_name");
|
typedef void (ChaiScript_System<Eval_Engine>::*load_mod_2)(const std::string&, const std::string&);
|
||||||
engine.add(fun(boost::function<bool (const std::string &)>(boost::bind(&Eval_Engine::function_exists, boost::ref(engine), _1))),
|
|
||||||
"function_exists");
|
|
||||||
|
|
||||||
engine.add(vector_type<std::vector<Boxed_Value> >("Vector"));
|
engine.add(fun(static_cast<load_mod_1>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
|
||||||
engine.add(string_type<std::string>("string"));
|
engine.add(fun(static_cast<load_mod_2>(&ChaiScript_System<Eval_Engine>::load_module), this), "load_module");
|
||||||
engine.add(map_type<std::map<std::string, Boxed_Value> >("Map"));
|
|
||||||
engine.add(pair_type<std::pair<Boxed_Value, Boxed_Value > >("Pair"));
|
|
||||||
|
|
||||||
engine.add(fun(boost::function<void (const std::string &)>(boost::bind(&ChaiScript_System<Eval_Engine>::use, this, _1))), "use");
|
|
||||||
|
|
||||||
engine.add(Proxy_Function(
|
add(vector_type<std::vector<Boxed_Value> >("Vector"));
|
||||||
new Dynamic_Proxy_Function(boost::bind(&ChaiScript_System<Eval_Engine>::internal_eval, boost::ref(*this), _1), 1)), "eval");
|
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");
|
do_eval(chaiscript_prelude, "standard prelude");
|
||||||
}
|
}
|
||||||
|
@@ -9,40 +9,39 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include <chaiscript/language/chaiscript_common.hpp>
|
||||||
|
|
||||||
namespace chaiscript
|
namespace chaiscript
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Helper function that will set up the scope around a function call, including handling the named function parameters
|
* Helper function that will set up the scope around a function call, including handling the named function parameters
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
const Boxed_Value eval_function (Eval_System &ss, TokenPtr node, const std::vector<std::string> ¶m_names, const std::vector<Boxed_Value> &vals) {
|
const Boxed_Value eval_function (Eval_System &ss, const TokenPtr &node, const std::vector<std::string> ¶m_names, const std::vector<Boxed_Value> &vals) {
|
||||||
ss.new_scope();
|
ss.new_scope();
|
||||||
|
|
||||||
for (unsigned int i = 0; i < param_names.size(); ++i) {
|
for (unsigned int i = 0; i < param_names.size(); ++i) {
|
||||||
ss.add_object(param_names[i], vals[i]);
|
ss.add_object(param_names[i], vals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Boxed_Value retval;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retval = eval_token(ss, node);
|
Boxed_Value retval(eval_token(ss, node));
|
||||||
ss.pop_scope();
|
ss.pop_scope();
|
||||||
|
return retval;
|
||||||
} catch (const Return_Value &rv) {
|
} catch (const Return_Value &rv) {
|
||||||
retval = rv.retval;
|
|
||||||
ss.pop_scope();
|
ss.pop_scope();
|
||||||
|
return rv.retval;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
ss.pop_scope();
|
ss.pop_scope();
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates the top-level file node
|
* Evaluates the top-level file node
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_file(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_file(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i = 0; i < node->children.size(); ++i) {
|
for (i = 0; i < node->children.size(); ++i) {
|
||||||
@@ -51,17 +50,44 @@ namespace chaiscript
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Eval_System>
|
||||||
|
void cache_const(Eval_System &/*ss*/, const TokenPtr &node, const Boxed_Value &value) {
|
||||||
|
node->cached_value = value;
|
||||||
|
node->is_cached = true;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Evaluates a variable or function name identifier
|
* Evaluates a variable or function name identifier
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_id(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_id(Eval_System &ss, const TokenPtr &node) {
|
||||||
|
|
||||||
if (node->text == "true") {
|
if (node->text == "true") {
|
||||||
return Boxed_Value(true);
|
//return const_var(true);
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(true));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
else if (node->text == "false") {
|
else if (node->text == "false") {
|
||||||
return Boxed_Value(false);
|
//return const_var(false);
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(false));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
|
}
|
||||||
|
else if (node->text == "Infinity") {
|
||||||
|
//return const_var(false);
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(std::numeric_limits<double>::infinity()));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
|
}
|
||||||
|
else if (node->text == "NaN") {
|
||||||
|
//return const_var(false);
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(std::numeric_limits<double>::quiet_NaN()));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
@@ -77,61 +103,83 @@ namespace chaiscript
|
|||||||
* Evaluates a floating point number
|
* Evaluates a floating point number
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_float(Eval_System &, TokenPtr node) {
|
Boxed_Value eval_float(Eval_System &ss, const TokenPtr &node) {
|
||||||
return Boxed_Value(double(atof(node->text.c_str())));
|
//return const_var(double(atof(node->text.c_str())));
|
||||||
|
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(double(atof(node->text.c_str()))));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates an integer
|
* Evaluates an integer
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_int(Eval_System &, TokenPtr node) {
|
Boxed_Value eval_int(Eval_System &ss, const TokenPtr &node) {
|
||||||
return Boxed_Value(atoi(node->text.c_str()));
|
//return const_var(atoi(node->text.c_str()));
|
||||||
|
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(int(atoi(node->text.c_str()))));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a quoted string
|
* Evaluates a quoted string
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_quoted_string(Eval_System &, TokenPtr node) {
|
Boxed_Value eval_quoted_string(Eval_System &ss, const TokenPtr &node) {
|
||||||
return Boxed_Value(node->text);
|
//return const_var(node->text);
|
||||||
|
|
||||||
|
/*
|
||||||
|
if ((node->text.size() > 0) && (node->text[0] == '$')) {
|
||||||
|
node->text.erase(0, 1);
|
||||||
|
Param_List_Builder plb;
|
||||||
|
plb << node->text;
|
||||||
|
|
||||||
|
return ss.call_function("eval", plb);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (!node->is_cached) {
|
||||||
|
cache_const(ss, node, const_var(node->text));
|
||||||
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a char group
|
* Evaluates a char group
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_single_quoted_string(Eval_System &, TokenPtr node) {
|
Boxed_Value eval_single_quoted_string(Eval_System &ss, const TokenPtr &node) {
|
||||||
if (node->text.size() == 1) {
|
if (!node->is_cached) {
|
||||||
return Boxed_Value(char(node->text[0]));
|
cache_const(ss, node, const_var(char(node->text[0])));
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Boxed_Value(char((int)node->text[0] * 0xff + (int)node->text[0]));
|
|
||||||
}
|
}
|
||||||
|
return node->cached_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a string of equations in reverse order so that the right-most side has precedence
|
* Evaluates a string of equations in reverse order so that the right-most side has precedence
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_equation(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_equation(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
int i;
|
||||||
unsigned int i;
|
Boxed_Value retval = eval_token(ss, node->children.back());
|
||||||
retval = eval_token(ss, node->children.back());
|
|
||||||
if (node->children.size() > 1) {
|
if (node->children.size() > 1) {
|
||||||
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
|
for (i = node->children.size()-3; i >= 0; i -= 2) {
|
||||||
if (node->children[i+1]->text == "=") {
|
if (node->children[i+1]->text == "=") {
|
||||||
Boxed_Value lhs = eval_token(ss, node->children[i]);
|
Boxed_Value lhs = eval_token(ss, node->children[i]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (lhs.is_unknown())
|
if (lhs.is_unknown())
|
||||||
{
|
{
|
||||||
retval = dispatch(ss.get_function("clone"), Param_List_Builder() << retval);
|
retval = ss.call_function("clone", Param_List_Builder() << retval);
|
||||||
}
|
}
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
plb << lhs;
|
plb << lhs;
|
||||||
plb << retval;
|
plb << retval;
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
|
retval = ss.call_function(node->children[i+1]->text, plb);
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &){
|
catch(const dispatch_error &){
|
||||||
throw Eval_Error("Mismatched types in equation", node->children[i+1]);
|
throw Eval_Error("Mismatched types in equation", node->children[i+1]);
|
||||||
@@ -155,7 +203,7 @@ namespace chaiscript
|
|||||||
plb << eval_token(ss, node->children[i]);
|
plb << eval_token(ss, node->children[i]);
|
||||||
plb << retval;
|
plb << retval;
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function(node->children[i+1]->text), plb);
|
retval = ss.call_function(node->children[i+1]->text, plb);
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &){
|
catch(const dispatch_error &){
|
||||||
throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]);
|
throw Eval_Error("Can not find appropriate '" + node->children[i+1]->text + "'", node->children[i+1]);
|
||||||
@@ -170,25 +218,40 @@ namespace chaiscript
|
|||||||
* Evaluates a variable declaration
|
* Evaluates a variable declaration
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_var_decl(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_var_decl(Eval_System &ss, const TokenPtr &node) {
|
||||||
try {
|
try {
|
||||||
ss.add_object(node->children[0]->text, Boxed_Value());
|
ss.add_object(node->children[0]->text, Boxed_Value());
|
||||||
}
|
}
|
||||||
catch (reserved_word_error &rwe) {
|
catch (reserved_word_error &) {
|
||||||
throw Eval_Error("Reserved word used as variable '" + node->children[0]->text + "'", node);
|
throw Eval_Error("Reserved word used as variable '" + node->children[0]->text + "'", node);
|
||||||
}
|
}
|
||||||
return ss.get_object(node->children[0]->text);
|
return ss.get_object(node->children[0]->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates an attribute declaration
|
||||||
|
*/
|
||||||
|
template <typename Eval_System>
|
||||||
|
Boxed_Value eval_attr_decl(Eval_System &ss, const TokenPtr &node) {
|
||||||
|
try {
|
||||||
|
ss.add(fun(boost::function<Boxed_Value (Dynamic_Object &)>(boost::bind(&Dynamic_Object_Attribute::func, node->children[0]->text,
|
||||||
|
node->children[1]->text, _1))), node->children[1]->text);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (reserved_word_error &) {
|
||||||
|
throw Eval_Error("Reserved word used as attribute '" + node->children[1]->text + "'", node);
|
||||||
|
}
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates binary boolean operators. Respects short-circuiting rules.
|
* Evaluates binary boolean operators. Respects short-circuiting rules.
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_expression(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_expression(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
if (node->children.size() > 1) {
|
if (node->children.size() > 1) {
|
||||||
for (i = 1; i < node->children.size(); i += 2) {
|
for (i = 1; i < node->children.size(); i += 2) {
|
||||||
bool lhs;
|
bool lhs;
|
||||||
@@ -223,11 +286,10 @@ namespace chaiscript
|
|||||||
* Evaluates comparison, additions, and multiplications and their relatives
|
* Evaluates comparison, additions, and multiplications and their relatives
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_comp_add_mul(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_comp_add_mul(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
if (node->children.size() > 1) {
|
if (node->children.size() > 1) {
|
||||||
for (i = 1; i < node->children.size(); i += 2) {
|
for (i = 1; i < node->children.size(); i += 2) {
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
@@ -235,7 +297,7 @@ namespace chaiscript
|
|||||||
plb << eval_token(ss, node->children[i + 1]);
|
plb << eval_token(ss, node->children[i + 1]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function(node->children[i]->text), plb);
|
retval = ss.call_function(node->children[i]->text, plb);
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &){
|
catch(const dispatch_error &){
|
||||||
throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]);
|
throw Eval_Error("Can not find appropriate '" + node->children[i]->text + "'", node->children[i]);
|
||||||
@@ -250,17 +312,16 @@ namespace chaiscript
|
|||||||
* Evaluates an array lookup
|
* Evaluates an array lookup
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_array_call(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_array_call(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
for (i = 1; i < node->children.size(); ++i) {
|
for (i = 1; i < node->children.size(); ++i) {
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
plb << retval;
|
plb << retval;
|
||||||
plb << eval_token(ss, node->children[i]);
|
plb << eval_token(ss, node->children[i]);
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function("[]"), plb);
|
retval = ss.call_function("[]", plb);
|
||||||
}
|
}
|
||||||
catch(std::out_of_range &) {
|
catch(std::out_of_range &) {
|
||||||
throw Eval_Error("Out of bounds exception", node);
|
throw Eval_Error("Out of bounds exception", node);
|
||||||
@@ -277,16 +338,14 @@ namespace chaiscript
|
|||||||
* Evaluates a unary negation
|
* Evaluates a unary negation
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_negate(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_negate(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
plb << retval;
|
plb << retval;
|
||||||
plb << Boxed_Value(-1.0);
|
plb << Boxed_Value(-1.0);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return dispatch(ss.get_function("*"), plb);
|
return ss.call_function("*", plb);
|
||||||
}
|
}
|
||||||
catch(std::exception &){
|
catch(std::exception &){
|
||||||
throw Eval_Error("Can not find appropriate negation", node->children[0]);
|
throw Eval_Error("Can not find appropriate negation", node->children[0]);
|
||||||
@@ -297,33 +356,25 @@ namespace chaiscript
|
|||||||
* Evaluates a unary boolean not
|
* Evaluates a unary boolean not
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_not(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_not(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
|
|
||||||
bool cond;
|
|
||||||
try {
|
try {
|
||||||
retval = eval_token(ss, node->children[0]);
|
return Boxed_Value(!boxed_cast<bool>(eval_token(ss, node->children[0])));
|
||||||
cond = boxed_cast<bool &>(retval);
|
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]);
|
throw Eval_Error("Boolean not('!') condition not boolean", node->children[0]);
|
||||||
}
|
}
|
||||||
return Boxed_Value(!cond);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates any unary prefix
|
* Evaluates any unary prefix
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_prefix(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_prefix(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[1]);
|
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
plb << retval;
|
plb << eval_token(ss, node->children[1]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return dispatch(ss.get_function(node->children[0]->text), plb);
|
return ss.call_function(node->children[0]->text, plb);
|
||||||
}
|
}
|
||||||
catch(std::exception &){
|
catch(std::exception &){
|
||||||
throw Eval_Error("Can not find appropriate prefix", node->children[0]);
|
throw Eval_Error("Can not find appropriate prefix", node->children[0]);
|
||||||
@@ -334,38 +385,38 @@ namespace chaiscript
|
|||||||
* Evaluates (and generates) an inline array initialization
|
* Evaluates (and generates) an inline array initialization
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_inline_array(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_inline_array(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function("Vector"), Param_List_Builder());
|
Boxed_Value retval = ss.call_function("Vector", Param_List_Builder());
|
||||||
if (node->children.size() > 0) {
|
if (node->children.size() > 0) {
|
||||||
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]);
|
Boxed_Value tmp = eval_token(ss, node->children[0]->children[i]);
|
||||||
dispatch(ss.get_function("push_back"), Param_List_Builder() << retval << tmp);
|
ss.call_function("push_back", Param_List_Builder() << retval << tmp);
|
||||||
}
|
}
|
||||||
catch (const dispatch_error &) {
|
catch (const dispatch_error &) {
|
||||||
throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]);
|
throw Eval_Error("Can not find appropriate 'push_back'", node->children[0]->children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
catch (const dispatch_error &) {
|
catch (const dispatch_error &) {
|
||||||
throw Eval_Error("Can not find appropriate 'Vector()'", node);
|
throw Eval_Error("Can not find appropriate 'Vector()'", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates (and generates) an inline range initialization
|
* Evaluates (and generates) an inline range initialization
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_inline_range(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_inline_range(Eval_System &ss, const TokenPtr &node) {
|
||||||
try {
|
try {
|
||||||
return dispatch(ss.get_function("generate_range"), Param_List_Builder()
|
return ss.call_function("generate_range", Param_List_Builder()
|
||||||
<< eval_token(ss, node->children[0]->children[0]->children[0])
|
<< eval_token(ss, node->children[0]->children[0]->children[0])
|
||||||
<< eval_token(ss, node->children[0]->children[0]->children[1]));
|
<< eval_token(ss, node->children[0]->children[0]->children[1]));
|
||||||
}
|
}
|
||||||
@@ -378,93 +429,122 @@ namespace chaiscript
|
|||||||
* Evaluates (and generates) an inline map initialization
|
* Evaluates (and generates) an inline map initialization
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_inline_map(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_inline_map(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
retval = dispatch(ss.get_function("Map"), Param_List_Builder());
|
Boxed_Value retval = ss.call_function("Map", Param_List_Builder());
|
||||||
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
for (i = 0; i < node->children[0]->children.size(); ++i) {
|
||||||
try {
|
try {
|
||||||
Boxed_Value key = eval_token(ss, node->children[0]->children[i]->children[0]);
|
Boxed_Value key = eval_token(ss, node->children[0]->children[i]->children[0]);
|
||||||
Boxed_Value slot = dispatch(ss.get_function("[]"), Param_List_Builder() << retval << key);
|
Boxed_Value slot = ss.call_function("[]", Param_List_Builder() << retval << key);
|
||||||
dispatch(ss.get_function("="), Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1]));
|
ss.call_function("=", Param_List_Builder() << slot << eval_token(ss, node->children[0]->children[i]->children[1]));
|
||||||
}
|
}
|
||||||
catch (const dispatch_error &) {
|
catch (const dispatch_error &) {
|
||||||
throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]);
|
throw Eval_Error("Can not find appropriate '=' for map init", node->children[0]->children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
catch (const dispatch_error &) {
|
catch (const dispatch_error &) {
|
||||||
throw Eval_Error("Can not find appropriate 'Map()'", node);
|
throw Eval_Error("Can not find appropriate 'Map()'", node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call.
|
* Evaluates a function call, starting with its arguments. Handles resetting the scope to the previous one after the call.
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_fun_call(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_fun_call(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
||||||
Dispatch_Engine::Stack new_stack = ss.new_stack();
|
Dispatch_Engine::Stack new_stack = ss.new_stack();
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
new_stack->push_back(Dispatch_Engine::Scope());
|
|
||||||
|
|
||||||
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
|
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
|
||||||
for (i = 0; i < node->children[1]->children.size(); ++i) {
|
for (i = 0; i < node->children[1]->children.size(); ++i) {
|
||||||
plb << eval_token(ss, node->children[1]->children[i]);
|
plb << eval_token(ss, node->children[1]->children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Boxed_Value fn;
|
|
||||||
try {
|
try {
|
||||||
fn = eval_token(ss, node->children[0]);
|
Boxed_Value fn = eval_token(ss, node->children[0]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ss.set_stack(new_stack);
|
||||||
|
Boxed_Value retval = (*boxed_cast<Const_Proxy_Function>(fn))(plb);
|
||||||
|
ss.set_stack(prev_stack);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
catch(const dispatch_error &e){
|
||||||
|
ss.set_stack(prev_stack);
|
||||||
|
throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]);
|
||||||
|
}
|
||||||
|
catch(Return_Value &rv) {
|
||||||
|
ss.set_stack(prev_stack);
|
||||||
|
return rv.retval;
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
ss.set_stack(prev_stack);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(Eval_Error &ee) {
|
catch(Eval_Error &ee) {
|
||||||
ss.set_stack(prev_stack);
|
ss.set_stack(prev_stack);
|
||||||
throw Eval_Error(ee.reason, node->children[0]);
|
throw Eval_Error(ee.reason, node->children[0]);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
ss.set_stack(new_stack);
|
}
|
||||||
retval = (*boxed_cast<Proxy_Function >(fn))(plb);
|
|
||||||
ss.set_stack(prev_stack);
|
/**
|
||||||
}
|
* Evaluates a function call, starting with its arguments. Does NOT change scope.
|
||||||
catch(const dispatch_error &e){
|
*/
|
||||||
ss.set_stack(prev_stack);
|
template <typename Eval_System>
|
||||||
throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]);
|
Boxed_Value eval_inplace_fun_call(Eval_System &ss, const TokenPtr &node) {
|
||||||
}
|
Param_List_Builder plb;
|
||||||
catch(Return_Value &rv) {
|
unsigned int i;
|
||||||
ss.set_stack(prev_stack);
|
|
||||||
retval = rv.retval;
|
if ((node->children.size() > 1) && (node->children[1]->identifier == Token_Type::Arg_List)) {
|
||||||
}
|
for (i = 0; i < node->children[1]->children.size(); ++i) {
|
||||||
catch(...) {
|
plb << eval_token(ss, node->children[1]->children[i]);
|
||||||
ss.set_stack(prev_stack);
|
}
|
||||||
throw;
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Boxed_Value fn = eval_token(ss, node->children[0]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Boxed_Value retval = (*boxed_cast<Const_Proxy_Function >(fn))(plb);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
catch(const dispatch_error &e){
|
||||||
|
throw Eval_Error(std::string(e.what()) + " with function '" + node->children[0]->text + "'", node->children[0]);
|
||||||
|
}
|
||||||
|
catch(Return_Value &rv) {
|
||||||
|
return rv.retval;
|
||||||
|
}
|
||||||
|
catch(...) {
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Eval_Error &ee) {
|
||||||
|
throw Eval_Error(ee.reason, node->children[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a method/attributes invocation
|
* Evaluates a method/attributes invocation
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_dot_access(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_dot_access(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
std::vector<std::pair<std::string, Proxy_Function > > fn;
|
|
||||||
Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
Dispatch_Engine::Stack prev_stack = ss.get_stack();
|
||||||
Dispatch_Engine::Stack new_stack = ss.new_stack();
|
Dispatch_Engine::Stack new_stack = ss.new_stack();
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
new_stack->push_back(Dispatch_Engine::Scope());
|
|
||||||
|
|
||||||
//todo: Please extract a single way of doing function calls between this and eval_fun_call
|
//todo: Please extract a single way of doing function calls between this and eval_fun_call
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
if (node->children.size() > 1) {
|
if (node->children.size() > 1) {
|
||||||
for (i = 1; i < node->children.size(); ++i) {
|
for (i = 1; i < node->children.size(); ++i) {
|
||||||
Param_List_Builder plb;
|
Param_List_Builder plb;
|
||||||
@@ -493,10 +573,8 @@ namespace chaiscript
|
|||||||
throw Eval_Error(ee.reason, node->children[i]);
|
throw Eval_Error(ee.reason, node->children[i]);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
//fn = ss.get_function(fun_name);
|
|
||||||
ss.set_stack(new_stack);
|
ss.set_stack(new_stack);
|
||||||
//retval = dispatch(fn, plb);
|
retval = (*boxed_cast<Const_Proxy_Function >(fn))(plb);
|
||||||
retval = (*boxed_cast<Proxy_Function >(fn))(plb);
|
|
||||||
ss.set_stack(prev_stack);
|
ss.set_stack(prev_stack);
|
||||||
}
|
}
|
||||||
catch(const dispatch_error &e){
|
catch(const dispatch_error &e){
|
||||||
@@ -521,14 +599,141 @@ namespace chaiscript
|
|||||||
* Evaluates an if/elseif/else block
|
* Evaluates an if/elseif/else block
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_if(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_try(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
|
retval = Boxed_Value();
|
||||||
|
|
||||||
|
ss.new_scope();
|
||||||
|
try {
|
||||||
|
retval = eval_token(ss, node->children[0]);
|
||||||
|
}
|
||||||
|
catch (const Eval_Error &) {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
catch (const std::exception &e) {
|
||||||
|
Boxed_Value except = Boxed_Value(boost::ref(e));
|
||||||
|
|
||||||
|
unsigned int end_point = node->children.size();
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
end_point = node->children.size() - 1;
|
||||||
|
}
|
||||||
|
for (unsigned int i = 1; i < end_point; ++i) {
|
||||||
|
TokenPtr catch_block = node->children[i];
|
||||||
|
|
||||||
|
if (catch_block->children.size() == 1) {
|
||||||
|
//No variable capture, no guards
|
||||||
|
retval = eval_token(ss, catch_block->children[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (catch_block->children.size() == 2) {
|
||||||
|
//Variable capture, no guards
|
||||||
|
ss.add_object(catch_block->children[0]->text, except);
|
||||||
|
retval = eval_token(ss, catch_block->children[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (catch_block->children.size() == 3) {
|
||||||
|
//Variable capture, no guards
|
||||||
|
ss.add_object(catch_block->children[0]->text, except);
|
||||||
|
|
||||||
|
bool guard;
|
||||||
|
try {
|
||||||
|
guard = boxed_cast<bool>(eval_token(ss, catch_block->children[1]));
|
||||||
|
} catch (const bad_boxed_cast &) {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw Eval_Error("Guard condition not boolean", catch_block->children[1]);
|
||||||
|
}
|
||||||
|
if (guard) {
|
||||||
|
retval = eval_token(ss, catch_block->children[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw Eval_Error("Internal error: catch block size unrecognized", catch_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Boxed_Value &bv) {
|
||||||
|
Boxed_Value except = bv;
|
||||||
|
for (unsigned int i = 1; i < node->children.size(); ++i) {
|
||||||
|
TokenPtr catch_block = node->children[i];
|
||||||
|
|
||||||
|
if (catch_block->children.size() == 1) {
|
||||||
|
//No variable capture, no guards
|
||||||
|
retval = eval_token(ss, catch_block->children[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (catch_block->children.size() == 2) {
|
||||||
|
//Variable capture, no guards
|
||||||
|
ss.add_object(catch_block->children[0]->text, except);
|
||||||
|
retval = eval_token(ss, catch_block->children[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (catch_block->children.size() == 3) {
|
||||||
|
//Variable capture, no guards
|
||||||
|
ss.add_object(catch_block->children[0]->text, except);
|
||||||
|
|
||||||
|
bool guard;
|
||||||
|
try {
|
||||||
|
guard = boxed_cast<bool>(eval_token(ss, catch_block->children[1]));
|
||||||
|
} catch (const bad_boxed_cast &) {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw Eval_Error("Guard condition not boolean", catch_block->children[1]);
|
||||||
|
}
|
||||||
|
if (guard) {
|
||||||
|
retval = eval_token(ss, catch_block->children[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw Eval_Error("Internal error: catch block size unrecognized", catch_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
ss.pop_scope();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
if (node->children.back()->identifier == Token_Type::Finally) {
|
||||||
|
retval = eval_token(ss, node->children.back()->children[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ss.pop_scope();
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates an if/elseif/else block
|
||||||
|
*/
|
||||||
|
template <typename Eval_System>
|
||||||
|
Boxed_Value eval_if(Eval_System &ss, const TokenPtr &node) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
retval = eval_token(ss, node->children[0]);
|
Boxed_Value retval = eval_token(ss, node->children[0]);
|
||||||
bool cond;
|
bool cond;
|
||||||
try {
|
try {
|
||||||
cond = boxed_cast<bool &>(retval);
|
cond = boxed_cast<bool>(retval);
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
throw Eval_Error("If condition not boolean", node->children[0]);
|
throw Eval_Error("If condition not boolean", node->children[0]);
|
||||||
@@ -547,7 +752,7 @@ namespace chaiscript
|
|||||||
else if (node->children[i]->text == "else if") {
|
else if (node->children[i]->text == "else if") {
|
||||||
retval = eval_token(ss, node->children[i+1]);
|
retval = eval_token(ss, node->children[i+1]);
|
||||||
try {
|
try {
|
||||||
cond = boxed_cast<bool &>(retval);
|
cond = boxed_cast<bool>(retval);
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
throw Eval_Error("'else if' condition not boolean", node->children[i+1]);
|
throw Eval_Error("'else if' condition not boolean", node->children[i+1]);
|
||||||
@@ -568,13 +773,13 @@ namespace chaiscript
|
|||||||
* Evaluates a while block
|
* Evaluates a while block
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_while(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_while(Eval_System &ss, const TokenPtr &node) {
|
||||||
bool cond;
|
bool cond;
|
||||||
|
|
||||||
ss.new_scope();
|
ss.new_scope();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[0]));
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
ss.pop_scope();
|
ss.pop_scope();
|
||||||
@@ -584,7 +789,7 @@ namespace chaiscript
|
|||||||
try {
|
try {
|
||||||
eval_token(ss, node->children[1]);
|
eval_token(ss, node->children[1]);
|
||||||
try {
|
try {
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[0]));
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
ss.pop_scope();
|
ss.pop_scope();
|
||||||
@@ -603,7 +808,7 @@ namespace chaiscript
|
|||||||
* Evaluates a for block, including the for's conditions, from left to right
|
* Evaluates a for block, including the for's conditions, from left to right
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_for(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_for(Eval_System &ss, const TokenPtr &node) {
|
||||||
bool cond;
|
bool cond;
|
||||||
|
|
||||||
ss.new_scope();
|
ss.new_scope();
|
||||||
@@ -611,10 +816,10 @@ namespace chaiscript
|
|||||||
try {
|
try {
|
||||||
if (node->children.size() == 4) {
|
if (node->children.size() == 4) {
|
||||||
eval_token(ss, node->children[0]);
|
eval_token(ss, node->children[0]);
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[1]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[1]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
@@ -626,12 +831,12 @@ namespace chaiscript
|
|||||||
if (node->children.size() == 4) {
|
if (node->children.size() == 4) {
|
||||||
eval_token(ss, node->children[3]);
|
eval_token(ss, node->children[3]);
|
||||||
eval_token(ss, node->children[2]);
|
eval_token(ss, node->children[2]);
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[1]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[1]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eval_token(ss, node->children[2]);
|
eval_token(ss, node->children[2]);
|
||||||
eval_token(ss, node->children[1]);
|
eval_token(ss, node->children[1]);
|
||||||
cond = boxed_cast<bool &>(eval_token(ss, node->children[0]));
|
cond = boxed_cast<bool>(eval_token(ss, node->children[0]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const bad_boxed_cast &) {
|
catch (const bad_boxed_cast &) {
|
||||||
@@ -650,8 +855,7 @@ namespace chaiscript
|
|||||||
* Evaluates a function definition
|
* Evaluates a function definition
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_def(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_def(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
std::vector<std::string> param_names;
|
std::vector<std::string> param_names;
|
||||||
@@ -694,18 +898,92 @@ namespace chaiscript
|
|||||||
param_names, _1), numparams,
|
param_names, _1), numparams,
|
||||||
annotation, guard)), function_name);
|
annotation, guard)), function_name);
|
||||||
}
|
}
|
||||||
catch (reserved_word_error &rwe) {
|
catch (reserved_word_error &) {
|
||||||
throw Eval_Error("Reserved word used as function name '" + function_name + "'", node);
|
throw Eval_Error("Reserved word used as function name '" + function_name + "'", node);
|
||||||
}
|
}
|
||||||
return retval;
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a function definition
|
||||||
|
*/
|
||||||
|
template <typename Eval_System>
|
||||||
|
Boxed_Value eval_def_method(Eval_System &ss, const TokenPtr &node) {
|
||||||
|
//TODO: Merge with eval_def cleanly someday?
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
std::vector<std::string> param_names;
|
||||||
|
std::string annotation = node->annotation?node->annotation->text:"";
|
||||||
|
boost::shared_ptr<Dynamic_Proxy_Function> guard;
|
||||||
|
size_t numparams;
|
||||||
|
std::string class_name = node->children[0]->text;
|
||||||
|
std::string function_name = node->children[1]->text;
|
||||||
|
TokenPtr guardnode;
|
||||||
|
|
||||||
|
//The first param of a method is always the implied this ptr.
|
||||||
|
param_names.push_back("this");
|
||||||
|
|
||||||
|
if ((node->children.size() > 3) && (node->children[2]->identifier == Token_Type::Arg_List)) {
|
||||||
|
for (i = 0; i < node->children[2]->children.size(); ++i) {
|
||||||
|
param_names.push_back(node->children[2]->children[i]->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->children.size() > 4) {
|
||||||
|
guardnode = node->children[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//no parameters
|
||||||
|
|
||||||
|
if (node->children.size() > 3) {
|
||||||
|
guardnode = node->children[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numparams = param_names.size();
|
||||||
|
|
||||||
|
if (guardnode) {
|
||||||
|
guard = boost::shared_ptr<Dynamic_Proxy_Function>
|
||||||
|
(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), guardnode,
|
||||||
|
param_names, _1), numparams));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (function_name == class_name) {
|
||||||
|
ss.add(Proxy_Function
|
||||||
|
(new Dynamic_Object_Constructor(class_name, Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), node->children.back(),
|
||||||
|
param_names, _1), numparams,
|
||||||
|
annotation, guard)))), function_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
boost::optional<chaiscript::Type_Info> ti;
|
||||||
|
try {
|
||||||
|
ti = ss.get_type(class_name);
|
||||||
|
} catch (const std::range_error &) {
|
||||||
|
// No biggie, the type name is just not known
|
||||||
|
}
|
||||||
|
ss.add(Proxy_Function
|
||||||
|
(new Dynamic_Object_Function(class_name, Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), node->children.back(),
|
||||||
|
param_names, _1), numparams,
|
||||||
|
annotation, guard)), ti)), function_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (reserved_word_error &) {
|
||||||
|
throw Eval_Error("Reserved word used as method name '" + function_name + "'", node);
|
||||||
|
}
|
||||||
|
return Boxed_Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a lambda (anonymous function)
|
* Evaluates a lambda (anonymous function)
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_lambda(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_lambda(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
std::vector<std::string> param_names;
|
std::vector<std::string> param_names;
|
||||||
@@ -732,7 +1010,7 @@ namespace chaiscript
|
|||||||
* Evaluates a scoped block. Handles resetting the scope after the block has completed.
|
* Evaluates a scoped block. Handles resetting the scope after the block has completed.
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_block(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_block(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
@@ -760,22 +1038,20 @@ namespace chaiscript
|
|||||||
* Evaluates a return statement
|
* Evaluates a return statement
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_return(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_return(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
|
||||||
if (node->children.size() > 0) {
|
if (node->children.size() > 0) {
|
||||||
retval = eval_token(ss, node->children[0]);
|
throw Return_Value(eval_token(ss, node->children[0]), node);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
retval = Boxed_Value();
|
throw Return_Value(Boxed_Value(), node);
|
||||||
}
|
}
|
||||||
throw Return_Value(retval, node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a break statement
|
* Evaluates a break statement
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_break(Eval_System &, TokenPtr node) {
|
Boxed_Value eval_break(Eval_System &, const TokenPtr &node) {
|
||||||
throw Break_Loop(node);
|
throw Break_Loop(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,7 +1059,7 @@ namespace chaiscript
|
|||||||
* Top-level evaluation dispatch for all AST node types
|
* Top-level evaluation dispatch for all AST node types
|
||||||
*/
|
*/
|
||||||
template <typename Eval_System>
|
template <typename Eval_System>
|
||||||
Boxed_Value eval_token(Eval_System &ss, TokenPtr node) {
|
Boxed_Value eval_token(Eval_System &ss, const TokenPtr &node) {
|
||||||
switch (node->identifier) {
|
switch (node->identifier) {
|
||||||
case (Token_Type::File) :
|
case (Token_Type::File) :
|
||||||
return eval_file(ss, node);
|
return eval_file(ss, node);
|
||||||
@@ -824,6 +1100,7 @@ namespace chaiscript
|
|||||||
case (Token_Type::Comparison) :
|
case (Token_Type::Comparison) :
|
||||||
case (Token_Type::Additive) :
|
case (Token_Type::Additive) :
|
||||||
case (Token_Type::Multiplicative) :
|
case (Token_Type::Multiplicative) :
|
||||||
|
case (Token_Type::Shift) :
|
||||||
return eval_comp_add_mul(ss, node);
|
return eval_comp_add_mul(ss, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -859,10 +1136,18 @@ namespace chaiscript
|
|||||||
return eval_fun_call(ss, node);
|
return eval_fun_call(ss, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (Token_Type::Inplace_Fun_Call) :
|
||||||
|
return eval_inplace_fun_call(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
case (Token_Type::Dot_Access) :
|
case (Token_Type::Dot_Access) :
|
||||||
return eval_dot_access(ss, node);
|
return eval_dot_access(ss, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case(Token_Type::Try) :
|
||||||
|
return eval_try(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
case(Token_Type::If) :
|
case(Token_Type::If) :
|
||||||
return eval_if(ss, node);
|
return eval_if(ss, node);
|
||||||
break;
|
break;
|
||||||
@@ -879,6 +1164,14 @@ namespace chaiscript
|
|||||||
return eval_def(ss, node);
|
return eval_def(ss, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (Token_Type::Method) :
|
||||||
|
return eval_def_method(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (Token_Type::Attr_Decl) :
|
||||||
|
return eval_attr_decl(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
case (Token_Type::Lambda) :
|
case (Token_Type::Lambda) :
|
||||||
return eval_lambda(ss, node);
|
return eval_lambda(ss, node);
|
||||||
break;
|
break;
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "chaiscript_prelude.hpp"
|
#include "chaiscript_prelude.hpp"
|
||||||
|
|
||||||
@@ -30,6 +31,9 @@ namespace chaiscript
|
|||||||
singleline_comment = "//";
|
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
|
* Prints the parsed tokens as a tree
|
||||||
*/
|
*/
|
||||||
@@ -68,7 +72,7 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
void build_match(Token_Type::Type match_type, int match_start) {
|
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
|
//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));
|
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());
|
t->children.assign(match_stack.begin() + (match_start), match_stack.end());
|
||||||
match_stack.erase(match_stack.begin() + (match_start), match_stack.end());
|
match_stack.erase(match_stack.begin() + (match_start), match_stack.end());
|
||||||
@@ -140,6 +144,8 @@ namespace chaiscript
|
|||||||
*/
|
*/
|
||||||
bool Float_() {
|
bool Float_() {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
std::string::iterator start = input_pos;
|
||||||
|
|
||||||
if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*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')) {
|
while ((input_pos != input_end) && (*input_pos >= '0') && (*input_pos <= '9')) {
|
||||||
++input_pos;
|
++input_pos;
|
||||||
@@ -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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a number from the input, detecting if it's an integer or floating point
|
* Reads a number from the input, detecting if it's an integer or floating point
|
||||||
*/
|
*/
|
||||||
@@ -172,13 +215,25 @@ namespace chaiscript
|
|||||||
SkipWS();
|
SkipWS();
|
||||||
|
|
||||||
if (!capture) {
|
if (!capture) {
|
||||||
return Float_();
|
return Hex_() || Float_();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string::iterator start = input_pos;
|
std::string::iterator start = input_pos;
|
||||||
int prev_col = col;
|
int prev_col = col;
|
||||||
int prev_line = line;
|
int prev_line = line;
|
||||||
if ((input_pos != input_end) && (((*input_pos >= '0') && (*input_pos <= '9')) || (*input_pos == '.')) ) {
|
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_()) {
|
if (Float_()) {
|
||||||
std::string match(start, input_pos);
|
std::string match(start, input_pos);
|
||||||
TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col));
|
TokenPtr t(new Token(match, Token_Type::Float, filename, prev_line, prev_col, line, col));
|
||||||
@@ -187,8 +242,20 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::string match(start, input_pos);
|
std::string match(start, input_pos);
|
||||||
TokenPtr t(new Token(match, Token_Type::Int, filename, prev_line, prev_col, line, col));
|
if ((match.size() > 0) && (match[0] == '0')) {
|
||||||
match_stack.push_back(t);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,7 +278,32 @@ namespace chaiscript
|
|||||||
++col;
|
++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;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,10 +321,19 @@ namespace chaiscript
|
|||||||
int prev_col = col;
|
int prev_col = col;
|
||||||
int prev_line = line;
|
int prev_line = line;
|
||||||
if (Id_()) {
|
if (Id_()) {
|
||||||
std::string match(start, input_pos);
|
if (*start == '`') {
|
||||||
TokenPtr t(new Token(match, Token_Type::Id, filename, prev_line, prev_col, line, col));
|
//Id Literal
|
||||||
match_stack.push_back(t);
|
std::string match(start+1, input_pos-1);
|
||||||
return true;
|
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 {
|
else {
|
||||||
return false;
|
return false;
|
||||||
@@ -323,37 +424,132 @@ namespace chaiscript
|
|||||||
if (Quoted_String_()) {
|
if (Quoted_String_()) {
|
||||||
std::string match;
|
std::string match;
|
||||||
bool is_escaped = false;
|
bool is_escaped = false;
|
||||||
for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) {
|
bool is_interpolated = false;
|
||||||
if (*s == '\\') {
|
bool saw_interpolation_marker = false;
|
||||||
if (is_escaped) {
|
int prev_stack_top = match_stack.size();
|
||||||
match.push_back('\\');
|
|
||||||
is_escaped = false;
|
//for (std::string::iterator s = start + 1, end = input_pos - 1; s != end; ++s) {
|
||||||
}
|
std::string::iterator s = start + 1, end = input_pos - 1;
|
||||||
else {
|
|
||||||
is_escaped = true;
|
while (s != end) {
|
||||||
}
|
if (saw_interpolation_marker) {
|
||||||
}
|
if (*s == '{') {
|
||||||
else {
|
//We've found an interpolation point
|
||||||
if (is_escaped) {
|
|
||||||
switch (*s) {
|
if (is_interpolated) {
|
||||||
case ('b') : match.push_back('\b'); break;
|
//If we've seen previous interpolation, add on instead of making a new one
|
||||||
case ('f') : match.push_back('\f'); break;
|
TokenPtr plus(new Token("+", Token_Type::Str, filename, prev_line, prev_col, line, col));
|
||||||
case ('n') : match.push_back('\n'); break;
|
match_stack.push_back(plus);
|
||||||
case ('r') : match.push_back('\r'); break;
|
|
||||||
case ('t') : match.push_back('\t'); break;
|
TokenPtr t(new Token(match, Token_Type::Quoted_String, filename, prev_line, prev_col, line, col));
|
||||||
case ('\'') : match.push_back('\''); break;
|
match_stack.push_back(t);
|
||||||
case ('\"') : match.push_back('\"'); break;
|
|
||||||
default: throw Eval_Error("Unknown escaped sequence in string", File_Position(prev_line, prev_col), filename);
|
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 {
|
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));
|
if (is_interpolated) {
|
||||||
match_stack.push_back(t);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -591,7 +787,7 @@ namespace chaiscript
|
|||||||
/**
|
/**
|
||||||
* Reads (and potentially captures) a symbol group from input if it matches the parameter
|
* 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();
|
SkipWS();
|
||||||
|
|
||||||
if (!capture) {
|
if (!capture) {
|
||||||
@@ -601,7 +797,7 @@ namespace chaiscript
|
|||||||
bool retval = Symbol_(s);
|
bool retval = Symbol_(s);
|
||||||
if (retval) {
|
if (retval) {
|
||||||
//todo: fix this. Hacky workaround for preventing substring matches
|
//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;
|
input_pos = start;
|
||||||
col = prev_col;
|
col = prev_col;
|
||||||
line = prev_line;
|
line = prev_line;
|
||||||
@@ -619,7 +815,7 @@ namespace chaiscript
|
|||||||
int prev_line = line;
|
int prev_line = line;
|
||||||
if (Symbol_(s)) {
|
if (Symbol_(s)) {
|
||||||
//todo: fix this. Hacky workaround for preventing substring matches
|
//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;
|
input_pos = start;
|
||||||
col = prev_col;
|
col = prev_col;
|
||||||
line = prev_line;
|
line = prev_line;
|
||||||
@@ -691,8 +887,10 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (Equation()) {
|
if (Equation()) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
while (Eol());
|
||||||
if (Char(',')) {
|
if (Char(',')) {
|
||||||
do {
|
do {
|
||||||
|
while (Eol());
|
||||||
if (!Equation()) {
|
if (!Equation()) {
|
||||||
throw Eval_Error("Unexpected value in parameter list", match_stack.back());
|
throw Eval_Error("Unexpected value in parameter list", match_stack.back());
|
||||||
}
|
}
|
||||||
@@ -718,8 +916,10 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
else if (Map_Pair()) {
|
else if (Map_Pair()) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
while (Eol());
|
||||||
if (Char(',')) {
|
if (Char(',')) {
|
||||||
do {
|
do {
|
||||||
|
while (Eol());
|
||||||
if (!Map_Pair()) {
|
if (!Map_Pair()) {
|
||||||
throw Eval_Error("Unexpected value in container", match_stack.back());
|
throw Eval_Error("Unexpected value in container", match_stack.back());
|
||||||
}
|
}
|
||||||
@@ -768,7 +968,7 @@ namespace chaiscript
|
|||||||
bool Def() {
|
bool Def() {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
bool is_annotated = false;
|
bool is_annotated = false;
|
||||||
|
bool is_method = false;
|
||||||
TokenPtr annotation;
|
TokenPtr annotation;
|
||||||
|
|
||||||
if (Annotation()) {
|
if (Annotation()) {
|
||||||
@@ -787,6 +987,15 @@ namespace chaiscript
|
|||||||
throw Eval_Error("Missing function name in definition", File_Position(line, col), filename);
|
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('(')) {
|
if (Char('(')) {
|
||||||
Arg_List();
|
Arg_List();
|
||||||
if (!Char(')')) {
|
if (!Char(')')) {
|
||||||
@@ -807,7 +1016,12 @@ namespace chaiscript
|
|||||||
throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
|
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) {
|
if (is_annotated) {
|
||||||
match_stack.back()->annotation = annotation;
|
match_stack.back()->annotation = annotation;
|
||||||
@@ -817,6 +1031,67 @@ namespace chaiscript
|
|||||||
return retval;
|
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
|
* Reads an if/elseif/else block from input
|
||||||
*/
|
*/
|
||||||
@@ -1022,7 +1297,7 @@ namespace chaiscript
|
|||||||
std::string::iterator prev_pos = input_pos;
|
std::string::iterator prev_pos = input_pos;
|
||||||
|
|
||||||
unsigned int prev_stack_top = match_stack.size();
|
unsigned int prev_stack_top = match_stack.size();
|
||||||
if (Id(true) || Id_Literal()) {
|
if (Id(true)) {
|
||||||
retval = true;
|
retval = true;
|
||||||
bool has_more = true;
|
bool has_more = true;
|
||||||
|
|
||||||
@@ -1071,6 +1346,22 @@ namespace chaiscript
|
|||||||
|
|
||||||
build_match(Token_Type::Var_Decl, prev_stack_top);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -1126,53 +1417,6 @@ namespace chaiscript
|
|||||||
return retval;
|
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
|
* Reads a unary prefixed expression from input
|
||||||
*/
|
*/
|
||||||
@@ -1181,24 +1425,6 @@ namespace chaiscript
|
|||||||
|
|
||||||
int prev_stack_top = match_stack.size();
|
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)) {
|
if (Symbol("++", true)) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
@@ -1217,6 +1443,24 @@ namespace chaiscript
|
|||||||
|
|
||||||
build_match(Token_Type::Prefix, prev_stack_top);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -1242,11 +1486,11 @@ namespace chaiscript
|
|||||||
|
|
||||||
int prev_stack_top = match_stack.size();
|
int prev_stack_top = match_stack.size();
|
||||||
|
|
||||||
if (Additive()) {
|
if (Shift()) {
|
||||||
retval = true;
|
retval = true;
|
||||||
if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) {
|
if (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)) {
|
||||||
do {
|
do {
|
||||||
if (!Additive()) {
|
if (!Shift()) {
|
||||||
throw Eval_Error("Incomplete comparison expression", File_Position(line, col), filename);
|
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)));
|
} while (retval && (Symbol(">=", true) || Symbol(">", true) || Symbol("<=", true) || Symbol("<", true) || Symbol("==", true) || Symbol("!=", true)));
|
||||||
@@ -1330,6 +1574,30 @@ namespace chaiscript
|
|||||||
return retval;
|
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
|
* Top-level expression, parses a string of binary boolean operators from input
|
||||||
*/
|
*/
|
||||||
@@ -1419,7 +1687,8 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (Expression()) {
|
if (Expression()) {
|
||||||
retval = true;
|
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()) {
|
if (!Equation()) {
|
||||||
throw Eval_Error("Incomplete equation", match_stack.back());
|
throw Eval_Error("Incomplete equation", match_stack.back());
|
||||||
}
|
}
|
||||||
@@ -1450,6 +1719,14 @@ namespace chaiscript
|
|||||||
retval = true;
|
retval = true;
|
||||||
saw_eol = 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()) {
|
else if (If()) {
|
||||||
if (!saw_eol) {
|
if (!saw_eol) {
|
||||||
throw Eval_Error("Two function definitions missing line separator", match_stack.back());
|
throw Eval_Error("Two function definitions missing line separator", match_stack.back());
|
||||||
@@ -1503,6 +1780,11 @@ namespace chaiscript
|
|||||||
retval = true;
|
retval = true;
|
||||||
saw_eol = true;
|
saw_eol = true;
|
||||||
}
|
}
|
||||||
|
else if (Block()) {
|
||||||
|
has_more = true;
|
||||||
|
retval = true;
|
||||||
|
saw_eol = true;
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
has_more = false;
|
has_more = false;
|
||||||
}
|
}
|
||||||
|
@@ -12,274 +12,318 @@
|
|||||||
#define CODE_STRING(x, y) #x ", " #y
|
#define CODE_STRING(x, y) #x ", " #y
|
||||||
|
|
||||||
#define chaiscript_prelude CODE_STRING(\
|
#define chaiscript_prelude CODE_STRING(\
|
||||||
def new(x) { eval(type_name(x))(); } \
|
def lt(l, r) { if (call_exists(`<`, l, r)) { l < r } else { type_name(l) < type_name(r) } } \n\
|
||||||
def clone(x) : function_exists(type_name(x)) { eval(type_name(x))(x); } \
|
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\
|
# to_string for Pair()\n\
|
||||||
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \
|
def to_string(x) : call_exists(first, x) && call_exists(second, x) { \n\
|
||||||
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \
|
"<" + x.first.to_string() + ", " + x.second.to_string() + ">"; \n\
|
||||||
}\
|
}\n\
|
||||||
# to_string for containers\n\
|
# to_string for containers\n\
|
||||||
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \
|
def to_string(x) : call_exists(range, x) && !x.is_type("string"){ \n\
|
||||||
"[" + x.join(", ") + "]"; \
|
"[" + x.join(", ") + "]"; \n\
|
||||||
}\
|
}\n\
|
||||||
# Basic to_string function\n\
|
# Basic to_string function\n\
|
||||||
def to_string(x) { \
|
def to_string(x) { \n\
|
||||||
internal_to_string(x); \
|
internal_to_string(x); \n\
|
||||||
}\
|
}\n\
|
||||||
# Prints to console with no carriage return\n\
|
# Prints to console with no carriage return\n\
|
||||||
def puts(x) { \
|
def puts(x) { \n\
|
||||||
print_string(x.to_string()); \
|
print_string(x.to_string()); \n\
|
||||||
} \
|
} \n\
|
||||||
# Prints to console with carriage return\n\
|
# Prints to console with carriage return\n\
|
||||||
def print(x) { \
|
def print(x) { \n\
|
||||||
println_string(x.to_string()); \
|
println_string(x.to_string()); \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns the maximum value of two numbers\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\
|
# 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\
|
# 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\
|
# 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\
|
# 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\
|
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\
|
# Inserts the third value at the position of the second value into the container of the first\n\
|
||||||
# while making a clone. \n\
|
# while making a clone. \n\
|
||||||
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
|
def insert_at(container, pos, x) { container.insert_ref_at(pos, clone(x)); } \n\
|
||||||
# Returns the reverse of the given container\n\
|
# Returns the reverse of the given container\n\
|
||||||
def reverse(container) {\
|
def reverse(container) {\n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
var r = retro(range(container)); \
|
var r = range(container); \n\
|
||||||
while (!r.empty()) { \
|
while (!r.empty()) { \n\
|
||||||
retval.push_back(r.front()); \
|
retval.push_back(r.back()); \n\
|
||||||
r.pop_front(); \
|
r.pop_back(); \n\
|
||||||
} \
|
} \n\
|
||||||
retval; \
|
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\
|
# Performs the second value function over the container first value\n\
|
||||||
def for_each(container, func) : call_exists(range, container) { \
|
def for_each(container, func) : call_exists(range, container) { \n\
|
||||||
var range = range(container); \
|
var t_range = range(container); \n\
|
||||||
while (!range.empty()) { \
|
while (!t_range.empty()) { \n\
|
||||||
func(range.front()); \
|
func(t_range.front()); \n\
|
||||||
range.pop_front(); \
|
t_range.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
def back_inserter(container) { \
|
def back_inserter(container) { \n\
|
||||||
bind(push_back, container, _); \
|
bind(push_back, container, _); \n\
|
||||||
}\
|
}\n\
|
||||||
\
|
\n\
|
||||||
def map(container, func, inserter) : call_exists(range, container) { \
|
def contains(container, item, compare_func) : call_exists(range, container) { \n\
|
||||||
var range = range(container); \
|
var t_range = range(container); \n\
|
||||||
while (!range.empty()) { \
|
while (!t_range.empty()) { \n\
|
||||||
inserter(func(range.front())); \
|
if ( compare_func(t_range.front(), item) ) { return true; } \n\
|
||||||
range.pop_front(); \
|
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\
|
# Performs the second value function over the container first value. Creates a new container with the results\n\
|
||||||
def map(container, func) { \
|
def map(container, func) { \n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
map(container, func, back_inserter(retval));\
|
map(container, func, back_inserter(retval));\n\
|
||||||
retval;\
|
retval;\n\
|
||||||
}\
|
}\n\
|
||||||
# Performs the second value function over the container first value. Starts with initial and continues with each element.\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){ \
|
def foldl(container, func, initial) : call_exists(range, container){ \n\
|
||||||
var retval = initial; \
|
var retval = initial; \n\
|
||||||
var range = range(container); \
|
var range = range(container); \n\
|
||||||
while (!range.empty()) { \
|
while (!range.empty()) { \n\
|
||||||
retval = (func(range.front(), retval)); \
|
retval = (func(range.front(), retval)); \n\
|
||||||
range.pop_front(); \
|
range.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns the sum of the elements of the given value\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\
|
# 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\
|
# 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) { \
|
def concat(x, y) : call_exists(clone, x) { \n\
|
||||||
var retval = x; \
|
var retval = x; \n\
|
||||||
var len = y.size(); \
|
var len = y.size(); \n\
|
||||||
var i = 0; \
|
var i = 0; \n\
|
||||||
while (i < len) { \
|
while (i < len) { \n\
|
||||||
retval.push_back(y[i]); \
|
retval.push_back(y[i]); \n\
|
||||||
++i; \
|
++i; \n\
|
||||||
} \
|
} \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
} \
|
} \n\
|
||||||
def take(container, num, inserter) : call_exists(range, container) { \
|
def take(container, num, inserter) : call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
var i = num; \
|
var i = num; \n\
|
||||||
while ((i > 0) && (!r.empty())) { \
|
while ((i > 0) && (!r.empty())) { \n\
|
||||||
inserter(r.front()); \
|
inserter(r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
--i; \
|
--i; \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new container with the given number of elements taken from the container\n\
|
# Returns a new container with the given number of elements taken from the container\n\
|
||||||
def take(container, num) {\
|
def take(container, num) {\n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
take(container, num, back_inserter(retval)); \
|
take(container, num, back_inserter(retval)); \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
}\
|
}\n\
|
||||||
def take_while(container, f, inserter) : call_exists(range, container) { \
|
def take_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
while ((!r.empty()) && f(r.front())) { \
|
while ((!r.empty()) && f(r.front())) { \n\
|
||||||
inserter(r.front()); \
|
inserter(r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new container with the given elements match the second value function\n\
|
# Returns a new container with the given elements match the second value function\n\
|
||||||
def take_while(container, f) {\
|
def take_while(container, f) {\n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
take_while(container, f, back_inserter(retval)); \
|
take_while(container, f, back_inserter(retval)); \n\
|
||||||
retval;\
|
retval;\n\
|
||||||
}\
|
}\n\
|
||||||
def drop(container, num, inserter) : call_exists(range, container) { \
|
def drop(container, num, inserter) : call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
var i = num; \
|
var i = num; \n\
|
||||||
while ((i > 0) && (!r.empty())) { \
|
while ((i > 0) && (!r.empty())) { \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
--i; \
|
--i; \n\
|
||||||
} \
|
} \n\
|
||||||
while (!r.empty()) { \
|
while (!r.empty()) { \n\
|
||||||
inserter(r.front()); \
|
inserter(r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new container with the given number of elements dropped from the given container \n\
|
# Returns a new container with the given number of elements dropped from the given container \n\
|
||||||
def drop(container, num) {\
|
def drop(container, num) {\n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
drop(container, num, back_inserter(retval)); \
|
drop(container, num, back_inserter(retval)); \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
}\
|
}\n\
|
||||||
def drop_while(container, f, inserter) : call_exists(range, container) { \
|
def drop_while(container, f, inserter) : call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
while ((!r.empty())&& f(r.front())) { \
|
while ((!r.empty())&& f(r.front())) { \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
while (!r.empty()) { \
|
while (!r.empty()) { \n\
|
||||||
inserter(r.front()); \
|
inserter(r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new container with the given elements dropped that match the second value function\n\
|
# Returns a new container with the given elements dropped that match the second value function\n\
|
||||||
def drop_while(container, f) {\
|
def drop_while(container, f) {\n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
drop_while(container, f, back_inserter(retval)); \
|
drop_while(container, f, back_inserter(retval)); \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
}\
|
}\n\
|
||||||
# Applies the second value function to the container. Starts with the first two elements. Expects at least 2 elements.\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) { \
|
def reduce(container, func) : container.size() >= 2 && call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
var retval = r.front(); \
|
var retval = r.front(); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
retval = func(retval, r.front()); \
|
retval = func(retval, r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
while (!r.empty()) { \
|
while (!r.empty()) { \n\
|
||||||
retval = func(retval, r.front()); \
|
retval = func(retval, r.front()); \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a string of the elements in container delimited by the second value string\n\
|
# Returns a string of the elements in container delimited by the second value string\n\
|
||||||
def join(container, delim) { \
|
def join(container, delim) { \n\
|
||||||
var retval = ""; \
|
var retval = ""; \n\
|
||||||
var range = range(container); \
|
var range = range(container); \n\
|
||||||
if (!range.empty()) { \
|
if (!range.empty()) { \n\
|
||||||
retval += to_string(range.front()); \
|
retval += to_string(range.front()); \n\
|
||||||
range.pop_front(); \
|
range.pop_front(); \n\
|
||||||
while (!range.empty()) { \
|
while (!range.empty()) { \n\
|
||||||
retval += delim; \
|
retval += delim; \n\
|
||||||
retval += to_string(range.front()); \
|
retval += to_string(range.front()); \n\
|
||||||
range.pop_front(); \
|
range.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
} \
|
} \n\
|
||||||
def filter(container, f, inserter) : call_exists(range, container) { \
|
def filter(container, f, inserter) : call_exists(range, container) { \n\
|
||||||
var r = range(container); \
|
var r = range(container); \n\
|
||||||
while (!r.empty()) { \
|
while (!r.empty()) { \n\
|
||||||
if (f(r.front())) { \
|
if (f(r.front())) { \n\
|
||||||
inserter(r.front()); \
|
inserter(r.front()); \n\
|
||||||
} \
|
} \n\
|
||||||
r.pop_front(); \
|
r.pop_front(); \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new Vector which match the second value function\n\
|
# Returns a new Vector which match the second value function\n\
|
||||||
def filter(container, f) { \
|
def filter(container, f) { \n\
|
||||||
var retval = new(container); \
|
var retval = new(container); \n\
|
||||||
filter(container, f, back_inserter(retval));\
|
filter(container, f, back_inserter(retval));\n\
|
||||||
retval;\
|
retval;\n\
|
||||||
}\
|
}\n\
|
||||||
def generate_range(x, y, inserter) { \
|
def generate_range(x, y, inserter) { \n\
|
||||||
var i = x; \
|
var i = x; \n\
|
||||||
while (i <= y) { \
|
while (i <= y) { \n\
|
||||||
inserter(i); \
|
inserter(i); \n\
|
||||||
++i; \
|
++i; \n\
|
||||||
} \
|
} \n\
|
||||||
} \
|
} \n\
|
||||||
# Returns a new Vector which represents the range from the first value to the second value\n\
|
# Returns a new Vector which represents the range from the first value to the second value\n\
|
||||||
def generate_range(x, y) { \
|
def generate_range(x, y) { \n\
|
||||||
var retval = Vector(); \
|
var retval = Vector(); \n\
|
||||||
generate_range(x,y,back_inserter(retval)); \
|
generate_range(x,y,back_inserter(retval)); \n\
|
||||||
retval; \
|
retval; \n\
|
||||||
}\
|
}\n\
|
||||||
# Returns a new Vector with the first value to the second value as its elements\n\
|
# Returns a new Vector with the first value to the second value as its elements\n\
|
||||||
def collate(x, y) { \
|
def collate(x, y) { \n\
|
||||||
[x, y]; \
|
[x, y]; \n\
|
||||||
} \
|
} \n\
|
||||||
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \
|
def zip_with(f, x, y, inserter) : call_exists(range, x) && call_exists(range, y) { \n\
|
||||||
var r_x = range(x); \
|
var r_x = range(x); \n\
|
||||||
var r_y = range(y); \
|
var r_y = range(y); \n\
|
||||||
while (!r_x.empty() && !r_y.empty()) { \
|
while (!r_x.empty() && !r_y.empty()) { \n\
|
||||||
inserter(f(r_x.front(), r_y.front())); \
|
inserter(f(r_x.front(), r_y.front())); \n\
|
||||||
r_x.pop_front(); \
|
r_x.pop_front(); \n\
|
||||||
r_y.pop_front(); \
|
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\
|
# 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) { \
|
def zip_with(f, x, y) { \n\
|
||||||
var retval = Vector(); \
|
var retval = Vector(); \n\
|
||||||
zip_with(f,x,y,back_inserter(retval)); \
|
zip_with(f,x,y,back_inserter(retval)); \n\
|
||||||
retval;\
|
retval;\n\
|
||||||
}\
|
}\n\
|
||||||
# Returns a new Vector which joins matching elements of the first and second\n\
|
# Returns a new Vector which joins matching elements of the first and second\n\
|
||||||
def zip(x, y) { \
|
def zip(x, y) { \n\
|
||||||
zip_with(collate, x, y); \
|
zip_with(collate, x, y); \n\
|
||||||
}\
|
}\n\
|
||||||
# Returns the position of the second value string in the first value string\n\
|
# Returns the position of the second value string in the first value string\n\
|
||||||
def find(str, substr) { \
|
def string::find(substr) : is_type(substr, "string") { \n\
|
||||||
int(find(str, substr, size_t(0))); \
|
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\
|
# Returns the position of last match of the second value string in the first value string\n\
|
||||||
def rfind(str, substr) { \
|
def string::rfind(substr) : is_type(substr, "string") { \n\
|
||||||
int(rfind(str, substr, size_t(-1))); \
|
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\
|
# 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) { \
|
def string::find_first_of(list) : is_type(list, "string") { \n\
|
||||||
int(find_first_of(str, list, size_t(0))); \
|
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\
|
# 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) { \
|
def string::find_last_of(list) : is_type(list, "string") { \n\
|
||||||
int(find_last_of(str, list, size_t(-1))); \
|
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\
|
# 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) { \
|
def string::find_first_not_of(list) : is_type(list, "string") { \n\
|
||||||
int(find_first_not_of(str, list, size_t(0))); \
|
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\
|
# 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) { \
|
def string::find_last_not_of(list) : is_type(list, "string") { \n\
|
||||||
int(find_last_not_of(str, list, size_t(-1))); \
|
int(find_last_not_of(this, list, size_t(-1))); \n\
|
||||||
} \
|
} \n\
|
||||||
def ltrim(str) { \
|
def string::ltrim() { \n\
|
||||||
drop_while(str, fun(x) { x == ' ' || x == '\t' }); \
|
drop_while(this, fun(x) { x == ' ' || x == '\t' }); \n\
|
||||||
} \
|
} \n\
|
||||||
def rtrim(str) { \
|
def string::rtrim() { \n\
|
||||||
reverse(drop_while(reverse(str), fun(x) { x == ' ' || x == '\t' })); \
|
reverse(drop_while(reverse(this), fun(x) { x == ' ' || x == '\t' })); \n\
|
||||||
} \
|
} \n\
|
||||||
def trim(str) { \
|
def string::trim() { \n\
|
||||||
ltrim(rtrim(str)); \
|
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_ */
|
#endif /* CHAISCRIPT_PRELUDE_HPP_ */
|
||||||
|
@@ -42,7 +42,7 @@
|
|||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="0"
|
Optimization="0"
|
||||||
AdditionalIncludeDirectories="C:\Programming\chaiscript\trunk\include"
|
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
@@ -117,6 +117,7 @@
|
|||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
Optimization="2"
|
Optimization="2"
|
||||||
EnableIntrinsicFunctions="true"
|
EnableIntrinsicFunctions="true"
|
||||||
|
AdditionalIncludeDirectories=""$(ProjectDir)\..\..\include""
|
||||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||||
RuntimeLibrary="2"
|
RuntimeLibrary="2"
|
||||||
EnableFunctionLevelLinking="true"
|
EnableFunctionLevelLinking="true"
|
||||||
|
@@ -6,7 +6,7 @@
|
|||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCLCompilerTool"
|
Name="VCCLCompilerTool"
|
||||||
AdditionalIncludeDirectories=""C:\Programming\Boost\include\boost-1_38""
|
AdditionalIncludeDirectories=""C:\boost\include\boost-1_38""
|
||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLibrarianTool"
|
Name="VCLibrarianTool"
|
||||||
@@ -14,6 +14,6 @@
|
|||||||
/>
|
/>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCLinkerTool"
|
Name="VCLinkerTool"
|
||||||
AdditionalLibraryDirectories="C:\Programming\Boost\lib"
|
AdditionalLibraryDirectories="C:\Boost\lib"
|
||||||
/>
|
/>
|
||||||
</VisualStudioPropertySheet>
|
</VisualStudioPropertySheet>
|
||||||
|
@@ -5,6 +5,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chaiscript", "chaiscript.vc
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chai-example", "..\chai-example\chai-example.vcproj", "{CE422E94-B360-4588-8C65-6A9BE80798F9}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "chai-example", "..\chai-example\chai-example.vcproj", "{CE422E94-B360-4588-8C65-6A9BE80798F9}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_module", "..\test_module\test_module.vcproj", "{775EDCC2-102F-4E75-A860-9AF398D04145}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
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}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.ActiveCfg = Release|Win32
|
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
{CE422E94-B360-4588-8C65-6A9BE80798F9}.Release|Win32.Build.0 = 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
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
ConfigurationType="1"
|
ConfigurationType="1"
|
||||||
InheritedPropertySheets=".\Boost.vsprops"
|
InheritedPropertySheets=".\Boost.vsprops"
|
||||||
UseOfMFC="2"
|
UseOfMFC="2"
|
||||||
CharacterSet="0"
|
CharacterSet="1"
|
||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCPreBuildEventTool"
|
Name="VCPreBuildEventTool"
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
MinimalRebuild="true"
|
MinimalRebuild="true"
|
||||||
BasicRuntimeChecks="3"
|
BasicRuntimeChecks="3"
|
||||||
RuntimeLibrary="3"
|
RuntimeLibrary="3"
|
||||||
DisableLanguageExtensions="true"
|
DisableLanguageExtensions="false"
|
||||||
TreatWChar_tAsBuiltInType="false"
|
TreatWChar_tAsBuiltInType="false"
|
||||||
UsePrecompiledHeader="0"
|
UsePrecompiledHeader="0"
|
||||||
WarningLevel="4"
|
WarningLevel="4"
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
IntermediateDirectory="$(ConfigurationName)"
|
IntermediateDirectory="$(ConfigurationName)"
|
||||||
ConfigurationType="1"
|
ConfigurationType="1"
|
||||||
InheritedPropertySheets=".\Boost.vsprops"
|
InheritedPropertySheets=".\Boost.vsprops"
|
||||||
CharacterSet="0"
|
CharacterSet="1"
|
||||||
WholeProgramOptimization="1"
|
WholeProgramOptimization="1"
|
||||||
>
|
>
|
||||||
<Tool
|
<Tool
|
||||||
@@ -221,10 +221,18 @@
|
|||||||
RelativePath="..\..\include\chaiscript\language\chaiscript_prelude.hpp"
|
RelativePath="..\..\include\chaiscript\language\chaiscript_prelude.hpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\chaiscript\chaiscript_threading.hpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\chaiscript\dispatchkit\dispatchkit.hpp"
|
RelativePath="..\..\include\chaiscript\dispatchkit\dispatchkit.hpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath="..\..\include\chaiscript\dispatchkit\dynamic_object.hpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
|
RelativePath="..\..\include\chaiscript\dispatchkit\function_call.hpp"
|
||||||
>
|
>
|
||||||
|
198
msvc/test_module/test_module.vcproj
Normal file
198
msvc/test_module/test_module.vcproj
Normal 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=""$(ProjectDir)\..\..\include""
|
||||||
|
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=""$(ProjectDir)\..\..\include""
|
||||||
|
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>
|
@@ -1,5 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
|
||||||
successes=0
|
successes=0
|
||||||
failures=0
|
failures=0
|
||||||
|
|
||||||
@@ -8,7 +9,7 @@ for file in unittests/*.chai
|
|||||||
do
|
do
|
||||||
tstname=${file%.*}
|
tstname=${file%.*}
|
||||||
tst="$tstname.txt"
|
tst="$tstname.txt"
|
||||||
./chaiscript_eval $file > /tmp/tstout.txt
|
LD_LIBRARY_PATH=. ./chaiscript_eval $file > /tmp/tstout.txt
|
||||||
diff $tst /tmp/tstout.txt
|
diff $tst /tmp/tstout.txt
|
||||||
if [ "$?" -eq "0" ]
|
if [ "$?" -eq "0" ]
|
||||||
then
|
then
|
||||||
|
27
run_unit_tests_win.sh
Normal file
27
run_unit_tests_win.sh
Normal 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"
|
@@ -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;
|
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
|
struct System
|
||||||
{
|
{
|
||||||
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
|
std::map<std::string, boost::function<std::string (const std::string &) > > m_callbacks;
|
||||||
@@ -45,7 +61,7 @@ struct System
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void take_shared_ptr(const boost::shared_ptr<std::string> &p)
|
void take_shared_ptr(const boost::shared_ptr<const std::string> &p)
|
||||||
{
|
{
|
||||||
std::cout << *p << std::endl;
|
std::cout << *p << std::endl;
|
||||||
}
|
}
|
||||||
@@ -59,6 +75,9 @@ int main(int argc, char *argv[]) {
|
|||||||
System system;
|
System system;
|
||||||
chai.add(var(&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.
|
//Register the two methods of the System structure.
|
||||||
chai.add(fun(&System::add_callback), "add_callback");
|
chai.add(fun(&System::add_callback), "add_callback");
|
||||||
chai.add(fun(&System::do_callbacks), "do_callbacks");
|
chai.add(fun(&System::do_callbacks), "do_callbacks");
|
||||||
@@ -91,7 +110,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
//Finally, it is possible to register any boost::function as a system function, in this
|
//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
|
//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
|
//Call bound version of do_callbacks
|
||||||
chai("do_callbacks()");
|
chai("do_callbacks()");
|
||||||
@@ -130,7 +149,19 @@ int main(int argc, char *argv[]) {
|
|||||||
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
|
chai.add(bootstrap::vector_type<std::vector<int> >("IntVector"));
|
||||||
|
|
||||||
|
|
||||||
chai("dump_system()");
|
// 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("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()");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
src/main.cpp
37
src/main.cpp
@@ -6,22 +6,48 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
#ifdef READLINE_AVAILABLE
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <chaiscript/chaiscript.hpp>
|
#include <chaiscript/chaiscript.hpp>
|
||||||
|
|
||||||
void print_help() {
|
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 << "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_system() - outputs all functions registered to the system" << std::endl;
|
||||||
std::cout << " dump_object(x) - dumps information about the given symbol" << 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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
std::string input;
|
std::string input;
|
||||||
chaiscript::ChaiScript chai;
|
chaiscript::ChaiScript chai;
|
||||||
|
|
||||||
|
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
std::cout << "eval> ";
|
//std::cout << "eval> ";
|
||||||
std::getline(std::cin, input);
|
//std::getline(std::cin, input);
|
||||||
|
#ifdef READLINE_AVAILABLE
|
||||||
|
using_history();
|
||||||
|
#endif
|
||||||
|
input = get_next_command();
|
||||||
while (input != "quit") {
|
while (input != "quit") {
|
||||||
|
|
||||||
chaiscript::Boxed_Value val;
|
chaiscript::Boxed_Value val;
|
||||||
@@ -35,7 +61,7 @@ int main(int argc, char *argv[]) {
|
|||||||
val = chai.eval(input);
|
val = chai.eval(input);
|
||||||
|
|
||||||
//Then, we try to print the result of the evaluation to the user
|
//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 {
|
try {
|
||||||
chaiscript::dispatch(chai.get_eval_engine().get_function("print"), chaiscript::Param_List_Builder() << val);
|
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> ";
|
input = get_next_command();
|
||||||
std::getline(std::cin, input);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
38
src/multithreaded.cpp
Normal file
38
src/multithreaded.cpp
Normal 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
9
src/stl_extra.cpp
Normal 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
16
src/test_module.cpp
Normal 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
10
src/work.chai
Normal 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);
|
||||||
|
}
|
1
unittests/block_start.chai
Normal file
1
unittests/block_start.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{print("hello")}
|
1
unittests/block_start.txt
Normal file
1
unittests/block_start.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
hello
|
4
unittests/equ_shortform.chai
Normal file
4
unittests/equ_shortform.chai
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var x=.5
|
||||||
|
print(x)
|
||||||
|
var y=-.5
|
||||||
|
print(y)
|
2
unittests/equ_shortform.txt
Normal file
2
unittests/equ_shortform.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
0.5
|
||||||
|
-0.5
|
9
unittests/exception.chai
Normal file
9
unittests/exception.chai
Normal 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
1
unittests/exception.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4
|
19
unittests/exception_finally.chai
Normal file
19
unittests/exception_finally.chai
Normal 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")
|
||||||
|
}
|
4
unittests/exception_finally.txt
Normal file
4
unittests/exception_finally.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
3
|
||||||
|
Finally #1
|
||||||
|
Safe
|
||||||
|
Finally #2
|
28
unittests/exception_guards.chai
Normal file
28
unittests/exception_guards.chai
Normal 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")
|
||||||
|
}
|
5
unittests/exception_guards.txt
Normal file
5
unittests/exception_guards.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
Catch 2: 2
|
||||||
|
Catch 2: 3
|
||||||
|
Catch 3: 4
|
||||||
|
Catch 3: 5
|
||||||
|
Backup catch
|
3
unittests/for_each_range.chai
Normal file
3
unittests/for_each_range.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var v = [1,2,3];
|
||||||
|
var r = range(v);
|
||||||
|
for_each(r, print)
|
3
unittests/for_each_range.txt
Normal file
3
unittests/for_each_range.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
3
unittests/for_each_retro.chai
Normal file
3
unittests/for_each_retro.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var v = [1,2,3];
|
||||||
|
var r = retro(range(v));
|
||||||
|
for_each(r, print)
|
3
unittests/for_each_retro.txt
Normal file
3
unittests/for_each_retro.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
3
|
||||||
|
2
|
||||||
|
1
|
3
unittests/function_reassignment.chai
Normal file
3
unittests/function_reassignment.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var x = `+`
|
||||||
|
x = `-`
|
||||||
|
print(x(5,4))
|
1
unittests/function_reassignment.txt
Normal file
1
unittests/function_reassignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1
|
3
unittests/instring_eval.chai
Normal file
3
unittests/instring_eval.chai
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
var bob = 5.5
|
||||||
|
print("${bob}")
|
||||||
|
print("val: ${5.5 + 2.5} and ${bob + 2.5}")
|
2
unittests/instring_eval.txt
Normal file
2
unittests/instring_eval.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
5.5
|
||||||
|
val: 8 and 8
|
4
unittests/instring_eval_more.chai
Normal file
4
unittests/instring_eval_more.chai
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
print("$ {4 + 5}")
|
||||||
|
print("$${4+5}")
|
||||||
|
print("Value: \${4 + 5}")
|
||||||
|
print("Value: \$${4 + 5}")
|
4
unittests/instring_eval_more.txt
Normal file
4
unittests/instring_eval_more.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
$ {4 + 5}
|
||||||
|
$9
|
||||||
|
Value: ${4 + 5}
|
||||||
|
Value: $9
|
1
unittests/invalid_function_assignment.chai
Normal file
1
unittests/invalid_function_assignment.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
clone = `-`
|
1
unittests/invalid_function_assignment.txt
Normal file
1
unittests/invalid_function_assignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Error: "Mismatched types in equation" in 'unittests/invalid_function_assignment.chai' at (1, 7)
|
2
unittests/invalid_function_reassignment.chai
Normal file
2
unittests/invalid_function_reassignment.chai
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
var x = 5
|
||||||
|
x = `-`
|
1
unittests/invalid_function_reassignment.txt
Normal file
1
unittests/invalid_function_reassignment.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Error: "Mismatched types in equation" in 'unittests/invalid_function_reassignment.chai' at (2, 3)
|
6
unittests/list_push_back.chai
Normal file
6
unittests/list_push_back.chai
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
load_module("stl_extra")
|
||||||
|
|
||||||
|
var x = List()
|
||||||
|
x.push_back(3)
|
||||||
|
x.push_back("A")
|
||||||
|
print(x)
|
1
unittests/list_push_back.txt
Normal file
1
unittests/list_push_back.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[3, A]
|
6
unittests/list_push_front.chai
Normal file
6
unittests/list_push_front.chai
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
load_module("stl_extra")
|
||||||
|
|
||||||
|
var x = List()
|
||||||
|
x.push_front(3)
|
||||||
|
x.push_front("A")
|
||||||
|
print(x)
|
1
unittests/list_push_front.txt
Normal file
1
unittests/list_push_front.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[A, 3]
|
2
unittests/load_module.chai
Normal file
2
unittests/load_module.chai
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
load_module("test")
|
||||||
|
print(hello_world())
|
1
unittests/load_module.txt
Normal file
1
unittests/load_module.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello World
|
10
unittests/loop_inner_outer.chai
Normal file
10
unittests/loop_inner_outer.chai
Normal 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)
|
||||||
|
|
1
unittests/loop_inner_outer.txt
Normal file
1
unittests/loop_inner_outer.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
100
|
@@ -1 +1,2 @@
|
|||||||
print(--3)
|
var i = 3
|
||||||
|
print(--i)
|
||||||
|
@@ -1 +1,2 @@
|
|||||||
print(++3)
|
var i = 3
|
||||||
|
print(++i)
|
||||||
|
7
unittests/multiline.chai
Normal file
7
unittests/multiline.chai
Normal 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
2
unittests/multiline.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[1, 2, 3, 4]
|
||||||
|
[2, 3, 4, 5]
|
2
unittests/number_formats.chai
Normal file
2
unittests/number_formats.chai
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
print(012)
|
||||||
|
print(0x1f)
|
2
unittests/number_formats.txt
Normal file
2
unittests/number_formats.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
10
|
||||||
|
31
|
5
unittests/object_attr.chai
Normal file
5
unittests/object_attr.chai
Normal 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))
|
1
unittests/object_attr.txt
Normal file
1
unittests/object_attr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7
|
11
unittests/object_clone.chai
Normal file
11
unittests/object_clone.chai
Normal 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);
|
2
unittests/object_clone.txt
Normal file
2
unittests/object_clone.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
10
|
||||||
|
20
|
5
unittests/object_constructor_guards.chai
Normal file
5
unittests/object_constructor_guards.chai
Normal 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)
|
2
unittests/object_constructor_guards.txt
Normal file
2
unittests/object_constructor_guards.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
constructed any old: 12
|
||||||
|
constructed less than 10: 3
|
7
unittests/object_method_guards.chai
Normal file
7
unittests/object_method_guards.chai
Normal 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)
|
2
unittests/object_method_guards.txt
Normal file
2
unittests/object_method_guards.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
e less than 10
|
||||||
|
e is some value
|
8
unittests/operator_overload.chai
Normal file
8
unittests/operator_overload.chai
Normal 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)
|
1
unittests/operator_overload.txt
Normal file
1
unittests/operator_overload.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9
|
8
unittests/operator_overload2.chai
Normal file
8
unittests/operator_overload2.chai
Normal 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)
|
1
unittests/operator_overload2.txt
Normal file
1
unittests/operator_overload2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-1
|
5
unittests/range_contains.chai
Normal file
5
unittests/range_contains.chai
Normal 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, `==`));
|
4
unittests/range_contains.txt
Normal file
4
unittests/range_contains.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
true
|
||||||
|
false
|
||||||
|
false
|
||||||
|
true
|
5
unittests/range_find.chai
Normal file
5
unittests/range_find.chai
Normal 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
2
unittests/range_find.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[Hi, 5.5]
|
||||||
|
[1, Hi, 5.5]
|
4
unittests/ref_equal.chai
Normal file
4
unittests/ref_equal.chai
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
var i = 3
|
||||||
|
var j := i
|
||||||
|
j = 4
|
||||||
|
print(i)
|
1
unittests/ref_equal.txt
Normal file
1
unittests/ref_equal.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4
|
7
unittests/retroretro.chai
Normal file
7
unittests/retroretro.chai
Normal 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
2
unittests/retroretro.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
2
|
||||||
|
3
|
6
unittests/runtime_error.chai
Normal file
6
unittests/runtime_error.chai
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
try {
|
||||||
|
throw(runtime_error("error"))
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
print(e.what())
|
||||||
|
}
|
1
unittests/runtime_error.txt
Normal file
1
unittests/runtime_error.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
error
|
1
unittests/shift.chai
Normal file
1
unittests/shift.chai
Normal file
@@ -0,0 +1 @@
|
|||||||
|
print(2 << 2)
|
1
unittests/shift.txt
Normal file
1
unittests/shift.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8
|
Reference in New Issue
Block a user