Merge branch 'develop' into method_missing
This commit is contained in:
commit
b67dc4e09a
@ -26,6 +26,14 @@ notifications:
|
|||||||
- jason@emptycrate.com
|
- jason@emptycrate.com
|
||||||
on_success: always
|
on_success: always
|
||||||
on_failure: always
|
on_failure: always
|
||||||
|
webhooks:
|
||||||
|
urls:
|
||||||
|
- https://webhooks.gitter.im/e/4be9a2720eaa1bb2a6c9
|
||||||
|
on_success: change # options: [always|never|change] default: always
|
||||||
|
on_failure: always # options: [always|never|change] default: always
|
||||||
|
on_start: false # default: false
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,16 @@
|
|||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
if(NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
|
||||||
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
IF(BIICODE)
|
||||||
|
INIT_BIICODE_BLOCK()
|
||||||
|
ADD_BIICODE_TARGETS()
|
||||||
|
ELSE()
|
||||||
|
# Your regular CMakeLists configuration here
|
||||||
|
|
||||||
|
|
||||||
project(chaiscript)
|
project(chaiscript)
|
||||||
|
|
||||||
# MINGW does not yet support C++11's concurrency features
|
# MINGW does not yet support C++11's concurrency features
|
||||||
@ -81,7 +92,7 @@ set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md")
|
|||||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description.txt")
|
||||||
|
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
set(CPACK_PACKAGE_VERSION_MAJOR 5)
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR 6)
|
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
set(CPACK_PACKAGE_EXECUTABLES "chai;ChaiScript Eval")
|
||||||
@ -409,3 +420,6 @@ configure_file(contrib/pkgconfig/chaiscript.pc.in lib/pkgconfig/chaiscript.pc @O
|
|||||||
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
install(FILES "${chaiscript_BINARY_DIR}/lib/pkgconfig/chaiscript.pc"
|
||||||
DESTINATION lib/pkgconfig)
|
DESTINATION lib/pkgconfig)
|
||||||
|
|
||||||
|
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
5
biicode.conf
Normal file
5
biicode.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[paths]
|
||||||
|
include
|
||||||
|
|
||||||
|
[parent]
|
||||||
|
ChaiScript/ChaiScript: 0
|
261
cheatsheet.md
Normal file
261
cheatsheet.md
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
# Initializing ChaiScript
|
||||||
|
|
||||||
|
```
|
||||||
|
chaiscript::ChaiScript chai; // loads stdlib from loadable module on file system
|
||||||
|
chaiscript::ChaiScript chai(chaiscript::Std_Lib::library()); // compiles in stdlib
|
||||||
|
```
|
||||||
|
|
||||||
|
# Adding Things To The Engine
|
||||||
|
|
||||||
|
## Adding a Function / Method / Member
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::fun(&function_name), "function_name");
|
||||||
|
chai.add(chaiscript::fun(&Class::method_name), "method_name");
|
||||||
|
chai.add(chaiscript::fun(&Class::member_name), "member_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Overloads
|
||||||
|
|
||||||
|
#### Preferred
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::fun<ReturnType (ParamType1, ParamType2)>(&function_with_overloads), "function_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Alternative
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::fun(std::static_cast<ReturnType (*)(ParamType1, ParamType2)>(&function_with_overloads)), "function_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lambda
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(
|
||||||
|
chaiscript::fun<std::string (bool)>(
|
||||||
|
[](bool type) {
|
||||||
|
if (type) { return "x"; }
|
||||||
|
else { return "y"; }
|
||||||
|
}), "function_name");
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructors
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::constructor<MyType ()>(), "MyType");
|
||||||
|
chai.add(chaiscript::constructor<MyType (const MyType &)>(), "MyType");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding Types
|
||||||
|
|
||||||
|
It's not strictly necessary to add types, but it helps with many things. Cloning, better errors, etc.
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::user_type<MyClass>, "MyClass");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding Objects
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.add(chaiscript::var(somevar), "somevar"); // copied in
|
||||||
|
chai.add(chaiscript::var(std::ref(somevar), "somevar"); // by reference, shared between C++ and chai
|
||||||
|
auto shareddouble = std::make_shared<double>(4.3);
|
||||||
|
chai.add(chaiscript::var(shareddouble), "shareddouble"); // by shared_ptr, shared between c++ and chai
|
||||||
|
chai.add(chaiscript::const_var(somevar), "somevar"); // copied in and made const
|
||||||
|
chai.add_global_const(chaiscript::const_var(somevar), "somevar"); // global const. Throws if value is non-const
|
||||||
|
chai.add_global(chaiscript::var(somevar), "somevar"); // global non-const
|
||||||
|
```
|
||||||
|
|
||||||
|
# Executing Script
|
||||||
|
|
||||||
|
## General
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.eval("print(\"Hello World\")");
|
||||||
|
chai.eval(R"(print("Hello World"))");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Unboxing Return Values
|
||||||
|
|
||||||
|
### Prefered
|
||||||
|
|
||||||
|
```
|
||||||
|
chai.eval<double>("5.3 + 2.1"); // returns 7.4 as a C++ double
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternative
|
||||||
|
|
||||||
|
```
|
||||||
|
auto v = chai.eval("5.3 + 2.1");
|
||||||
|
chai.boxed_cast<double>(v); // extracts double value from boxed_value and applies known conversions
|
||||||
|
chaiscript::boxed_cast<double>(v); // free function version, does not know about conversions
|
||||||
|
```
|
||||||
|
|
||||||
|
### Converting Between Algebraic Types
|
||||||
|
|
||||||
|
```
|
||||||
|
chaiscript::Boxed_Number(chai.eval("5.3 + 2.1")).get_as<int>(); // works with any number type
|
||||||
|
// which is equivalent to, but much more automatic than:
|
||||||
|
static_cast<int>(chai.eval<double>("5.3+2.1")); // this version only works if we know that it's a double
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sharing Values
|
||||||
|
|
||||||
|
```
|
||||||
|
double &d = chai.eval("var i = 5.2; i"); // d is now a reference to i in the script
|
||||||
|
std::shared_ptr<double> d = chai.eval("var i = 5.2; i"); // same result but reference counted
|
||||||
|
|
||||||
|
d = 3;
|
||||||
|
chai.eval("print(i)"); // prints 3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Catching Eval Errors
|
||||||
|
|
||||||
|
```
|
||||||
|
try {
|
||||||
|
chai.eval("2.3 + \"String\"");
|
||||||
|
} catch (const chaiscript::exception::eval_error &e) {
|
||||||
|
std::cout << "Error\n" << e.pretty_print() << '\n';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Catching Errors Thrown From Script
|
||||||
|
|
||||||
|
```
|
||||||
|
try {
|
||||||
|
chai.eval("throw(runtime_error(\"error\"))", chaiscript::exception_specification<int, double, float, const std::string &, const std::exception &>());
|
||||||
|
} catch (const double e) {
|
||||||
|
} catch (int) {
|
||||||
|
} catch (float) {
|
||||||
|
} catch (const std::string &) {
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
// This is the one what will be called in the specific throw() above
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sharing Functions
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
auto p = chai.eval<std::function<std::string (double)>>("to_string");
|
||||||
|
p(5); // calls chaiscript's 'to_string' function, returning std::string("5")
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: backtick treats operators as normal functions
|
||||||
|
|
||||||
|
```
|
||||||
|
auto p = chai.eval<std::function<int (int, int)>>(`+`);
|
||||||
|
p(5, 6); // calls chaiscript's '+' function, returning 11
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
auto p = chai.eval<std::function<std::string (int, double)>>(fun(x,y) { to_string(x) + to_string(y); });
|
||||||
|
p(3,4.2); // evaluates the lambda function, returning the string "34.2" to C++
|
||||||
|
```
|
||||||
|
|
||||||
|
# Language Reference
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
```
|
||||||
|
var i; // uninitialized variable, can take any value on first assignment;
|
||||||
|
auto j; // equiv to var
|
||||||
|
|
||||||
|
var k = 5; // initialized to 5 (integer)
|
||||||
|
var l := k; // reference to k
|
||||||
|
auto &m = k; // reference to k
|
||||||
|
```
|
||||||
|
|
||||||
|
## Built in Types
|
||||||
|
|
||||||
|
```
|
||||||
|
var v = [1,2,3u,4ll,"16", `+`]; // creates vector of heterogenous values
|
||||||
|
var m = ["a":1, "b":2]; // map of string:value pairs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
|
||||||
|
### General
|
||||||
|
|
||||||
|
```
|
||||||
|
def myfun(x, y) { x + y; } // last statement in body is the return value
|
||||||
|
def myfun(x, y) { return x + y; } // equiv
|
||||||
|
```
|
||||||
|
|
||||||
|
### Optionally Typed
|
||||||
|
|
||||||
|
```
|
||||||
|
def myfun(x, int y) { x + y; } // requires y to be an int
|
||||||
|
```
|
||||||
|
|
||||||
|
### With Guards
|
||||||
|
|
||||||
|
```
|
||||||
|
def myfun(x, int y) : y > 5 { x - y; } // only called if y > 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
|
||||||
|
Methods and functions are mostly equivalent
|
||||||
|
|
||||||
|
```
|
||||||
|
def string::add(int y) { this + to_string(y); }
|
||||||
|
def add(string s, int y) { s + to_string(y); } //equiv functionality
|
||||||
|
|
||||||
|
// calling new function/method
|
||||||
|
"a".add(1); // returns a1
|
||||||
|
add("a", 1); // returns a1, either calling syntax works with either def above
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lambdas
|
||||||
|
|
||||||
|
```
|
||||||
|
var l = fun(x) { x * 15; }
|
||||||
|
l(2) // returns 30
|
||||||
|
|
||||||
|
var a = 13
|
||||||
|
var m = fun[a](x) { x * a; }
|
||||||
|
m(3); // a was captured (by reference), returns 39
|
||||||
|
|
||||||
|
var n = bind(fun(x,y) { x * y; }, _, 10);
|
||||||
|
n(2); // returns 20
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## ChaiScript Defined Types
|
||||||
|
|
||||||
|
Define a type called "MyType" with one member value "a" and a getter
|
||||||
|
|
||||||
|
### Preferred
|
||||||
|
|
||||||
|
```
|
||||||
|
class MyType {
|
||||||
|
var value;
|
||||||
|
def MyType() { this.value = "a"; }
|
||||||
|
def get_value() { "Value Is: " + this.value; }
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Alternative
|
||||||
|
|
||||||
|
```
|
||||||
|
attr MyType::value;
|
||||||
|
def MyType::MyType() { this.value = "a"; }
|
||||||
|
def MyType::get_value() { "Value Is: " + this.value; }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using
|
||||||
|
|
||||||
|
```
|
||||||
|
var m = MyType(); // calls constructor
|
||||||
|
print(m.get_value()); // prints "Value Is: a"
|
||||||
|
print(get_value(m)); // prints "Value Is: a"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
22
contrib/codeanalysis/type_conversions.chai
Normal file
22
contrib/codeanalysis/type_conversions.chai
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
load_module("test_module")
|
||||||
|
|
||||||
|
auto t := TestBaseType();
|
||||||
|
|
||||||
|
// This uses the TestBaseType to Type2 user type
|
||||||
|
// conversion which was added in the module and then calls
|
||||||
|
// "get_val()" which exists on the Type2 type
|
||||||
|
//assert_equal(t.get_val(), 10);
|
||||||
|
//print("Made it past test 1");
|
||||||
|
|
||||||
|
var t2 := Type2(t);
|
||||||
|
|
||||||
|
//dump_system();
|
||||||
|
|
||||||
|
for (var i = 0; i < 50000; ++i) {
|
||||||
|
var str = string(get_str(t2));
|
||||||
|
size(get_str(t2));
|
||||||
|
t2.get_str().size();
|
||||||
|
t.get_str().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -10,6 +10,9 @@
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define CHAISCRIPT_MSVC _MSC_VER
|
#define CHAISCRIPT_MSVC _MSC_VER
|
||||||
#define CHAISCRIPT_HAS_DECLSPEC
|
#define CHAISCRIPT_HAS_DECLSPEC
|
||||||
|
#if _MSC_VER <= 1800
|
||||||
|
#define CHAISCRIPT_MSVC_12
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
@ -45,7 +48,7 @@
|
|||||||
|
|
||||||
namespace chaiscript {
|
namespace chaiscript {
|
||||||
static const int version_major = 5;
|
static const int version_major = 5;
|
||||||
static const int version_minor = 6;
|
static const int version_minor = 7;
|
||||||
static const int version_patch = 0;
|
static const int version_patch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (itr != m_instances.end()) { return itr->second; }
|
if (itr != m_instances.end()) { return itr->second; }
|
||||||
|
|
||||||
std::shared_ptr<T> new_instance(new T());
|
std::shared_ptr<T> new_instance(std::make_shared<T>());
|
||||||
|
|
||||||
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
m_instances.insert(std::make_pair(std::this_thread::get_id(), new_instance));
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ namespace chaiscript
|
|||||||
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||||
{
|
{
|
||||||
m->add(fun(&detail::insert_at<ContainerType>),
|
m->add(fun(&detail::insert_at<ContainerType>),
|
||||||
[](){
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
return "insert_ref_at";
|
return "insert_ref_at";
|
||||||
} else {
|
} else {
|
||||||
@ -329,7 +329,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||||
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||||
[](){
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
return "push_back_ref";
|
return "push_back_ref";
|
||||||
} else {
|
} else {
|
||||||
@ -357,7 +357,7 @@ namespace chaiscript
|
|||||||
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
|
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
|
||||||
|
|
||||||
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)),
|
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)),
|
||||||
[](){
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||||
return "push_front_ref";
|
return "push_front_ref";
|
||||||
} else {
|
} else {
|
||||||
@ -418,7 +418,7 @@ namespace chaiscript
|
|||||||
m->add(fun(&detail::insert<ContainerType>), "insert");
|
m->add(fun(&detail::insert<ContainerType>), "insert");
|
||||||
|
|
||||||
m->add(fun(&detail::insert_ref<ContainerType>),
|
m->add(fun(&detail::insert_ref<ContainerType>),
|
||||||
[](){
|
[]()->std::string{
|
||||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
||||||
return "insert_ref";
|
return "insert_ref";
|
||||||
} else {
|
} else {
|
||||||
@ -538,7 +538,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
||||||
m->add(fun(&String::push_back),
|
m->add(fun(&String::push_back),
|
||||||
[](){
|
[]()->std::string{
|
||||||
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
||||||
return "push_back_ref";
|
return "push_back_ref";
|
||||||
} else {
|
} else {
|
||||||
|
@ -74,9 +74,12 @@ namespace chaiscript
|
|||||||
template<typename Type>
|
template<typename Type>
|
||||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
|
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
|
||||||
{
|
{
|
||||||
|
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
|
||||||
try {
|
try {
|
||||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef CHAISCRIPT_MSVC
|
#ifdef CHAISCRIPT_MSVC
|
||||||
@ -112,8 +115,6 @@ namespace chaiscript
|
|||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -641,6 +641,7 @@ namespace chaiscript
|
|||||||
/// \throws std::range_error if it does not
|
/// \throws std::range_error if it does not
|
||||||
Boxed_Value get_function_object(const std::string &t_name) const
|
Boxed_Value get_function_object(const std::string &t_name) const
|
||||||
{
|
{
|
||||||
|
// std::cout << "Getting function object: " << t_name << '\n';
|
||||||
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
chaiscript::detail::threading::shared_lock<chaiscript::detail::threading::shared_mutex> l(m_mutex);
|
||||||
|
|
||||||
const auto &funs = get_function_objects_int();
|
const auto &funs = get_function_objects_int();
|
||||||
|
@ -30,7 +30,7 @@ namespace chaiscript
|
|||||||
Proxy_Function build_constructor_(Class (*)(Params...))
|
Proxy_Function build_constructor_(Class (*)(Params...))
|
||||||
{
|
{
|
||||||
typedef std::shared_ptr<Class> (sig)(Params...);
|
typedef std::shared_ptr<Class> (sig)(Params...);
|
||||||
return Proxy_Function(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>))));
|
return Proxy_Function(static_cast<Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<sig>(std::function<sig>(&(constructor_<Class, Params...>)))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,6 +180,8 @@ namespace chaiscript
|
|||||||
if (m_arity == 0)
|
if (m_arity == 0)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
} else if (m_arity > 1 && m_types.size() > 1) {
|
||||||
|
return compare_first_type(vals[0], t_conversions) && compare_type_to_param(m_types[2], vals[1], t_conversions);
|
||||||
} else {
|
} else {
|
||||||
return compare_first_type(vals[0], t_conversions);
|
return compare_first_type(vals[0], t_conversions);
|
||||||
}
|
}
|
||||||
@ -233,14 +235,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
|
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const
|
||||||
{
|
{
|
||||||
const auto &types = get_param_types();
|
return compare_type_to_param(m_types[1], bv, t_conversions);
|
||||||
|
|
||||||
if (types.size() < 2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return compare_type_to_param(types[1], bv, t_conversions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
|
static bool compare_types(const std::vector<Type_Info> &tis, const std::vector<Boxed_Value> &bvs)
|
||||||
@ -779,7 +774,7 @@ namespace chaiscript
|
|||||||
Boxed_Value dispatch(const Funcs &funcs,
|
Boxed_Value dispatch(const Funcs &funcs,
|
||||||
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
|
const std::vector<Boxed_Value> &plist, const Type_Conversions &t_conversions)
|
||||||
{
|
{
|
||||||
|
//std::cout << "starting dispatch: " << funcs.size() << '\n';
|
||||||
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
|
std::multimap<size_t, const Proxy_Function_Base *> ordered_funcs;
|
||||||
|
|
||||||
for (const auto &func : funcs)
|
for (const auto &func : funcs)
|
||||||
@ -808,11 +803,17 @@ namespace chaiscript
|
|||||||
for (const auto &func : ordered_funcs )
|
for (const auto &func : ordered_funcs )
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
if (func.second->filter(plist, t_conversions))
|
if (func.first == 0 || func.second->filter(plist, t_conversions))
|
||||||
{
|
{
|
||||||
return (*(func.second))(plist, t_conversions);
|
return (*(func.second))(plist, t_conversions);
|
||||||
}
|
}
|
||||||
} catch (const exception::bad_boxed_cast &) {
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
|
//std::cout << "Bad Boxed Cast: " << func.second->get_arity() << '(';
|
||||||
|
//for (const auto &p : plist) {
|
||||||
|
// std::cout << p.get_type_info().name() << ',';
|
||||||
|
//}
|
||||||
|
//std::cout << ")\n";
|
||||||
|
|
||||||
//parameter failed to cast, try again
|
//parameter failed to cast, try again
|
||||||
} catch (const exception::arity_error &) {
|
} catch (const exception::arity_error &) {
|
||||||
//invalid num params, try again
|
//invalid num params, try again
|
||||||
|
@ -40,17 +40,25 @@ namespace chaiscript
|
|||||||
template<typename Ret, typename Class, typename ... Args>
|
template<typename Ret, typename Class, typename ... Args>
|
||||||
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
std::function<Ret (Class &, Args...) > to_function(Ret (Class::*func)(Args...))
|
||||||
{
|
{
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||||
/// std::function for member function pointers seems to be broken in MSVC
|
/// std::function for member function pointers seems to be broken in MSVC
|
||||||
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
|
return std::function<Ret(Class &, Args...)>(std::mem_fn(func));
|
||||||
|
#else
|
||||||
|
return std::function<Ret(Class &, Args...)>(func);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Ret, typename Class, typename ... Args>
|
template<typename Ret, typename Class, typename ... Args>
|
||||||
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
std::function<Ret (const Class &, Args...) > to_function(Ret (Class::*func)(Args...) const)
|
||||||
{
|
{
|
||||||
|
#ifdef CHAISCRIPT_MSVC
|
||||||
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
/// \todo this std::mem_fn wrap shouldn't be necessary but type conversions for
|
||||||
/// std::function for member function pointers seems to be broken in MSVC
|
/// std::function for member function pointers seems to be broken in MSVC
|
||||||
return std::function<Ret(const Class &, Args...)>(std::mem_fn(func));
|
return std::function<Ret(const Class &, Args...)>(std::mem_fn(func));
|
||||||
|
#else
|
||||||
|
return std::function<Ret(const Class &, Args...)>(func);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool Object>
|
template<bool Object>
|
||||||
@ -61,7 +69,7 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
/// \todo is it possible to reduce the number of templates generated here?
|
/// \todo is it possible to reduce the number of templates generated here?
|
||||||
return Proxy_Function(
|
return Proxy_Function(
|
||||||
new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t)));
|
static_cast<dispatch::Proxy_Function_Impl_Base *>(new Proxy_Function_Impl<typename FunctionSignature<decltype(to_function(t)) >::Signature>(to_function(t))));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -118,7 +126,7 @@ namespace chaiscript
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
Proxy_Function fun(const std::function<T> &f)
|
Proxy_Function fun(const std::function<T> &f)
|
||||||
{
|
{
|
||||||
return Proxy_Function(new dispatch::Proxy_Function_Impl<T>(f));
|
return Proxy_Function(static_cast<dispatch::Proxy_Function_Impl_Base *>(new dispatch::Proxy_Function_Impl<T>(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -467,14 +467,14 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname,
|
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname,
|
||||||
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
int t_start_line, int t_start_col, int t_end_line, int t_end_col) :
|
||||||
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
|
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname),
|
||||||
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
start(t_start_line, t_start_col), end(t_end_line, t_end_col)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<std::string> &t_fname) :
|
AST_Node(std::string t_ast_node_text, int t_id, const std::shared_ptr<const std::string> &t_fname) :
|
||||||
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
|
text(std::move(t_ast_node_text)), identifier(t_id), filename(t_fname) {}
|
||||||
|
|
||||||
virtual ~AST_Node() {}
|
virtual ~AST_Node() {}
|
||||||
@ -495,7 +495,6 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
/// Special type for returned values
|
/// Special type for returned values
|
||||||
struct Return_Value {
|
struct Return_Value {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
|
@ -276,7 +276,7 @@ namespace chaiscript
|
|||||||
parser::ChaiScript_Parser parser;
|
parser::ChaiScript_Parser parser;
|
||||||
if (parser.parse(t_input, t_filename)) {
|
if (parser.parse(t_input, t_filename)) {
|
||||||
//parser.show_match_stack();
|
//parser.show_match_stack();
|
||||||
return parser.ast()->eval(m_engine);
|
return parser.optimized_ast()->eval(m_engine);
|
||||||
} else {
|
} else {
|
||||||
return Boxed_Value();
|
return Boxed_Value();
|
||||||
}
|
}
|
||||||
|
@ -47,9 +47,13 @@ namespace chaiscript
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
/// 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
|
||||||
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals) {
|
static Boxed_Value eval_function(chaiscript::detail::Dispatch_Engine &t_ss, const AST_NodePtr &t_node, const std::vector<std::string> &t_param_names, const std::vector<Boxed_Value> &t_vals, const std::map<std::string, Boxed_Value> &t_locals=std::map<std::string, Boxed_Value>()) {
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
|
for (const auto &local : t_locals) {
|
||||||
|
t_ss.add_object(local.first, local.second);
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < t_param_names.size(); ++i) {
|
for (size_t i = 0; i < t_param_names.size(); ++i) {
|
||||||
t_ss.add_object(t_param_names[i], t_vals[i]);
|
t_ss.add_object(t_param_names[i], t_vals[i]);
|
||||||
}
|
}
|
||||||
@ -214,6 +218,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Fun_Call_AST_Node : public AST_Node {
|
struct Fun_Call_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
Fun_Call_AST_Node(const std::string &t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||||
@ -222,16 +227,15 @@ namespace chaiscript
|
|||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
|
|
||||||
|
|
||||||
std::vector<Boxed_Value> params;
|
std::vector<Boxed_Value> params;
|
||||||
|
|
||||||
if ((this->children.size() > 1)) {
|
if ((this->children.size() > 1)) {
|
||||||
const AST_Node &first_child(*(this->children[1]));
|
params.reserve(this->children[1]->children.size());
|
||||||
if (first_child.identifier == AST_Node_Type::Arg_List) {
|
for (const auto &child : this->children[1]->children) {
|
||||||
for (const auto &child : first_child.children) {
|
|
||||||
params.push_back(child->eval(t_ss));
|
params.push_back(child->eval(t_ss));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fpp.save_params(params);
|
fpp.save_params(params);
|
||||||
|
|
||||||
@ -286,6 +290,96 @@ namespace chaiscript
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Fun_Lookup_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Fun_Lookup_AST_Node(const std::string &t_fun_name)
|
||||||
|
: AST_Node(t_fun_name, 0, std::make_shared<std::string>("<EVAL>"))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Fun_Lookup_AST_Node() {}
|
||||||
|
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||||
|
try {
|
||||||
|
Boxed_Value bv = t_ss.get_object(text);
|
||||||
|
t_ss.add_object(text, bv);
|
||||||
|
std::cout << " Saved fun lookup: " << text << '\n';
|
||||||
|
return bv;
|
||||||
|
} catch (...) {
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Unary_Fun_Call_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Unary_Fun_Call_AST_Node(const Fun_Call_AST_Node &t_fc)
|
||||||
|
: AST_Node(t_fc.text, t_fc.identifier, t_fc.filename, t_fc.start.line, t_fc.start.column, t_fc.end.line, t_fc.end.column)
|
||||||
|
{
|
||||||
|
this->children = t_fc.children;
|
||||||
|
}
|
||||||
|
virtual ~Unary_Fun_Call_AST_Node() {}
|
||||||
|
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
|
|
||||||
|
std::vector<Boxed_Value> params{children[1]->children[0]->eval(t_ss)};
|
||||||
|
fpp.save_params(params);
|
||||||
|
|
||||||
|
Boxed_Value fn(this->children[0]->eval(t_ss));
|
||||||
|
|
||||||
|
try {
|
||||||
|
chaiscript::eval::detail::Stack_Push_Pop spp(t_ss);
|
||||||
|
return (*t_ss.boxed_cast<const Const_Proxy_Function &>(fn))(params, t_ss.conversions());
|
||||||
|
}
|
||||||
|
catch(const exception::dispatch_error &e){
|
||||||
|
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'", e.parameters, e.functions, false, t_ss);
|
||||||
|
}
|
||||||
|
catch(const exception::bad_boxed_cast &){
|
||||||
|
try {
|
||||||
|
Const_Proxy_Function f = t_ss.boxed_cast<const Const_Proxy_Function &>(fn);
|
||||||
|
// handle the case where there is only 1 function to try to call and dispatch fails on it
|
||||||
|
throw exception::eval_error("Error calling function '" + this->children[0]->text + "'", params, {f}, false, t_ss);
|
||||||
|
} catch (const exception::bad_boxed_cast &) {
|
||||||
|
throw exception::eval_error("'" + this->children[0]->pretty_print() + "' does not evaluate to a function.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const exception::arity_error &e){
|
||||||
|
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||||
|
}
|
||||||
|
catch(const exception::guard_error &e){
|
||||||
|
throw exception::eval_error(std::string(e.what()) + " with function '" + this->children[0]->text + "'");
|
||||||
|
}
|
||||||
|
catch(detail::Return_Value &rv) {
|
||||||
|
return rv.retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
||||||
|
{
|
||||||
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (const auto &child : this->children) {
|
||||||
|
oss << child->pretty_print();
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
oss << "(";
|
||||||
|
}
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
oss << ")";
|
||||||
|
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Used in the context of in-string ${} evals, so that no new scope is created
|
/// Used in the context of in-string ${} evals, so that no new scope is created
|
||||||
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
@ -446,26 +540,28 @@ namespace chaiscript
|
|||||||
struct Equation_AST_Node : public AST_Node {
|
struct Equation_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Equation_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
Equation_AST_Node(std::string t_ast_node_text = "", const std::shared_ptr<std::string> &t_fname=std::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||||
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col)
|
AST_Node(std::move(t_ast_node_text), AST_Node_Type::Equation, t_fname, t_start_line, t_start_col, t_end_line, t_end_col),
|
||||||
|
m_oper(Operators::invalid)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
Operators::Opers m_oper;
|
||||||
|
|
||||||
virtual ~Equation_AST_Node() {}
|
virtual ~Equation_AST_Node() {}
|
||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||||
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
chaiscript::eval::detail::Function_Push_Pop fpp(t_ss);
|
||||||
Boxed_Value rhs = this->children.back()->eval(t_ss);
|
Boxed_Value rhs = this->children[2]->eval(t_ss);
|
||||||
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
Boxed_Value lhs = this->children[0]->eval(t_ss);
|
||||||
|
|
||||||
Operators::Opers oper = Operators::to_operator(this->children[1]->text);
|
|
||||||
|
|
||||||
if (oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
|
if (m_oper != Operators::invalid && lhs.get_type_info().is_arithmetic() &&
|
||||||
rhs.get_type_info().is_arithmetic())
|
rhs.get_type_info().is_arithmetic())
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Boxed_Number::do_oper(oper, lhs, rhs);
|
return Boxed_Number::do_oper(m_oper, lhs, rhs);
|
||||||
} catch (const std::exception &) {
|
} catch (const std::exception &) {
|
||||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
||||||
}
|
}
|
||||||
} else if (oper == Operators::assign) {
|
} else if (m_oper == Operators::assign) {
|
||||||
try {
|
try {
|
||||||
if (lhs.is_undef()) {
|
if (lhs.is_undef()) {
|
||||||
if (!this->children.empty() &&
|
if (!this->children.empty() &&
|
||||||
@ -701,28 +797,31 @@ namespace chaiscript
|
|||||||
virtual ~Lambda_AST_Node() {}
|
virtual ~Lambda_AST_Node() {}
|
||||||
|
|
||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
std::vector<std::string> t_param_names;
|
|
||||||
|
|
||||||
size_t numparams = 0;
|
|
||||||
|
|
||||||
dispatch::Param_Types param_types;
|
const auto captures = [&]()->std::map<std::string, Boxed_Value>{
|
||||||
|
std::map<std::string, Boxed_Value> named_captures;
|
||||||
if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) {
|
for (const auto &capture : children[0]->children) {
|
||||||
numparams = this->children[0]->children.size();
|
named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
|
||||||
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[0]);
|
|
||||||
param_types = Arg_List_AST_Node::get_arg_types(this->children[0], t_ss);
|
|
||||||
}
|
}
|
||||||
|
return named_captures;
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto numparams = this->children[1]->children.size();
|
||||||
|
const auto param_names = Arg_List_AST_Node::get_arg_names(this->children[1]);
|
||||||
|
const auto param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
|
||||||
|
|
||||||
const auto &lambda_node = this->children.back();
|
const auto &lambda_node = this->children.back();
|
||||||
|
|
||||||
return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
|
return Boxed_Value(Proxy_Function(new dispatch::Dynamic_Proxy_Function(
|
||||||
[&t_ss, lambda_node, t_param_names](const std::vector<Boxed_Value> &t_params)
|
[&t_ss, lambda_node, param_names, captures](const std::vector<Boxed_Value> &t_params)
|
||||||
{
|
{
|
||||||
return detail::eval_function(t_ss, lambda_node, t_param_names, t_params);
|
return detail::eval_function(t_ss, lambda_node, param_names, t_params, captures);
|
||||||
},
|
},
|
||||||
static_cast<int>(numparams), lambda_node, param_types)));
|
static_cast<int>(numparams), lambda_node, param_types)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Block_AST_Node : public AST_Node {
|
struct Block_AST_Node : public AST_Node {
|
||||||
@ -732,25 +831,14 @@ namespace chaiscript
|
|||||||
virtual ~Block_AST_Node() {}
|
virtual ~Block_AST_Node() {}
|
||||||
|
|
||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
const auto num_children = this->children.size();
|
|
||||||
|
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
for (size_t i = 0; i < num_children; ++i) {
|
const auto num_children = children.size();
|
||||||
try {
|
for (size_t i = 0; i < num_children-1; ++i) {
|
||||||
if (i + 1 < num_children)
|
children[i]->eval(t_ss);
|
||||||
{
|
|
||||||
this->children[i]->eval(t_ss);
|
|
||||||
} else {
|
|
||||||
return this->children[i]->eval(t_ss);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const chaiscript::eval::detail::Return_Value &) {
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return children.back()->eval(t_ss);
|
||||||
|
|
||||||
return Boxed_Value();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -883,8 +971,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
if (get_bool_condition(this->children[0]->eval(t_ss))) {
|
if (get_bool_condition(this->children[0]->eval(t_ss))) {
|
||||||
return this->children[1]->eval(t_ss);
|
return this->children[1]->eval(t_ss);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (this->children.size() > 2) {
|
if (this->children.size() > 2) {
|
||||||
size_t i = 2;
|
size_t i = 2;
|
||||||
bool cond = false;
|
bool cond = false;
|
||||||
@ -917,26 +1004,22 @@ namespace chaiscript
|
|||||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
// initial expression
|
|
||||||
this->children[0]->eval(t_ss);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// while condition evals to true
|
for (
|
||||||
while (get_bool_condition(this->children[1]->eval(t_ss))) {
|
children[0]->eval(t_ss);
|
||||||
|
get_bool_condition(children[1]->eval(t_ss));
|
||||||
|
children[2]->eval(t_ss)
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
// Body of Loop
|
// Body of Loop
|
||||||
this->children[3]->eval(t_ss);
|
children[3]->eval(t_ss);
|
||||||
} catch (detail::Continue_Loop &) {
|
} catch (detail::Continue_Loop &) {
|
||||||
// we got a continue exception, which means all of the remaining
|
// we got a continue exception, which means all of the remaining
|
||||||
// loop implementation is skipped and we just need to continue to
|
// loop implementation is skipped and we just need to continue to
|
||||||
// the next iteration step
|
// the next iteration step
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop expression
|
|
||||||
this->children[2]->eval(t_ss);
|
|
||||||
}
|
}
|
||||||
}
|
} catch (detail::Break_Loop &) {
|
||||||
catch (detail::Break_Loop &) {
|
|
||||||
// loop broken
|
// loop broken
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,7 +1471,7 @@ namespace chaiscript
|
|||||||
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
|
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
|
||||||
(std::bind(chaiscript::eval::detail::eval_function,
|
(std::bind(chaiscript::eval::detail::eval_function,
|
||||||
std::ref(t_ss), guardnode,
|
std::ref(t_ss), guardnode,
|
||||||
t_param_names, std::placeholders::_1), static_cast<int>(numparams), guardnode);
|
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), guardnode);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1399,7 +1482,7 @@ namespace chaiscript
|
|||||||
if (function_name == class_name) {
|
if (function_name == class_name) {
|
||||||
param_types.push_front(class_name, Type_Info());
|
param_types.push_front(class_name, Type_Info());
|
||||||
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
t_ss.add(std::make_shared<dispatch::detail::Dynamic_Object_Constructor>(class_name, std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||||
std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1),
|
std::ref(t_ss), this->children.back(), t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()),
|
||||||
static_cast<int>(numparams), this->children.back(), param_types, l_annotation, guard)),
|
static_cast<int>(numparams), this->children.back(), param_types, l_annotation, guard)),
|
||||||
function_name);
|
function_name);
|
||||||
|
|
||||||
@ -1415,7 +1498,7 @@ namespace chaiscript
|
|||||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||||
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||||
std::ref(t_ss), this->children.back(),
|
std::ref(t_ss), this->children.back(),
|
||||||
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
|
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), this->children.back(),
|
||||||
param_types, l_annotation, guard), type), function_name);
|
param_types, l_annotation, guard), type), function_name);
|
||||||
} catch (const std::range_error &) {
|
} catch (const std::range_error &) {
|
||||||
param_types.push_front(class_name, Type_Info());
|
param_types.push_front(class_name, Type_Info());
|
||||||
@ -1424,7 +1507,7 @@ namespace chaiscript
|
|||||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
std::make_shared<dispatch::detail::Dynamic_Object_Function>(class_name,
|
||||||
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
std::make_shared<dispatch::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||||
std::ref(t_ss), this->children.back(),
|
std::ref(t_ss), this->children.back(),
|
||||||
t_param_names, std::placeholders::_1), static_cast<int>(numparams), this->children.back(),
|
t_param_names, std::placeholders::_1, std::map<std::string, Boxed_Value>()), static_cast<int>(numparams), this->children.back(),
|
||||||
param_types, l_annotation, guard)), function_name);
|
param_types, l_annotation, guard)), function_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -196,6 +196,127 @@ namespace chaiscript
|
|||||||
return m_match_stack.front();
|
return m_match_stack.front();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::map<std::string, int> count_fun_calls(const AST_NodePtr &p, bool in_loop) {
|
||||||
|
if (p->identifier == AST_Node_Type::Fun_Call) {
|
||||||
|
if (p->children[0]->identifier == AST_Node_Type::Id) {
|
||||||
|
return std::map<std::string, int>{{p->children[0]->text, in_loop?99:1}};
|
||||||
|
}
|
||||||
|
return std::map<std::string, int>();
|
||||||
|
} else {
|
||||||
|
std::map<std::string, int> counts;
|
||||||
|
for (const auto &child : p->children) {
|
||||||
|
auto childcounts = count_fun_calls(child, in_loop || p->identifier == AST_Node_Type::For || p->identifier == AST_Node_Type::While);
|
||||||
|
for (const auto &count : childcounts) {
|
||||||
|
counts[count.first] += count.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return counts;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optimize_fun_lookups(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (c->identifier == AST_Node_Type::Def
|
||||||
|
|| c->identifier == AST_Node_Type::Method
|
||||||
|
|| c->identifier == AST_Node_Type::Lambda) {
|
||||||
|
std::vector<AST_NodePtr> children_to_add;
|
||||||
|
auto counts = count_fun_calls(c, false);
|
||||||
|
for (const auto &count : counts) {
|
||||||
|
// std::cout << " Fun Call Count: " << count.first << " " << count.second << '\n';
|
||||||
|
if (count.second > 1) {
|
||||||
|
children_to_add.push_back(std::make_shared<eval::Fun_Lookup_AST_Node>(count.first));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c->children.back()->children.insert(c->children.back()->children.begin(), children_to_add.begin(), children_to_add.end());
|
||||||
|
}
|
||||||
|
optimize_fun_lookups(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void optimize_blocks(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
if (c->identifier == AST_Node_Type::Block) {
|
||||||
|
if (c->children.size() == 1) {
|
||||||
|
// std::cout << "swapping out block child for block\n";
|
||||||
|
c = c->children[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
optimize_blocks(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optimize_returns(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
if (c->identifier == AST_Node_Type::Def && c->children.size() > 0) {
|
||||||
|
auto &lastchild = c->children.back();
|
||||||
|
if (lastchild->identifier == AST_Node_Type::Block) {
|
||||||
|
auto &blocklastchild = lastchild->children.back();
|
||||||
|
if (blocklastchild->identifier == AST_Node_Type::Return) {
|
||||||
|
if (blocklastchild->children.size() == 1) {
|
||||||
|
blocklastchild = blocklastchild->children[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
optimize_returns(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void optimize_fun_calls(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
for (auto &c : p->children)
|
||||||
|
{
|
||||||
|
if (c->identifier == AST_Node_Type::Fun_Call && c->children.size() == 2 && c->children[1]->children.size() == 1) {
|
||||||
|
c = std::make_shared<eval::Unary_Fun_Call_AST_Node>(dynamic_cast<eval::Fun_Call_AST_Node &>(*c));
|
||||||
|
// std::cout << "optimized unary fun call\n";
|
||||||
|
}
|
||||||
|
optimize_fun_calls(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fixup_opers(AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
if (p->identifier == AST_Node_Type::Equation)
|
||||||
|
{
|
||||||
|
dynamic_cast<eval::Equation_AST_Node &>(*p).m_oper = Operators::to_operator(p->children[1]->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &c : p->children) {
|
||||||
|
fixup_opers(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int count_nodes(const AST_NodePtr &p)
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
for (auto &c : p->children) {
|
||||||
|
count += count_nodes(c);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
AST_NodePtr optimized_ast(bool t_optimize_blocks = false, bool t_optimize_returns = true, bool t_optimize_fun_lookups = false,
|
||||||
|
bool t_optimize_fun_calls = false) {
|
||||||
|
AST_NodePtr p = m_match_stack.front();
|
||||||
|
fixup_opers(p);
|
||||||
|
//Note, optimize_blocks is currently broken; it breaks stack management
|
||||||
|
if (t_optimize_blocks) { optimize_blocks(p); }
|
||||||
|
if (t_optimize_returns) { optimize_returns(p); }
|
||||||
|
if (t_optimize_fun_lookups) { optimize_fun_lookups(p); }
|
||||||
|
if (t_optimize_fun_calls) { optimize_fun_calls(p); }
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node
|
/// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node
|
||||||
void build_match(AST_NodePtr t_t, size_t t_match_start) {
|
void build_match(AST_NodePtr t_t, size_t t_match_start) {
|
||||||
int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop;
|
int pos_line_start, pos_col_start, pos_line_stop, pos_col_stop;
|
||||||
@ -692,7 +813,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an argument from input
|
/// Reads an argument from input
|
||||||
bool Arg() {
|
bool Arg(const bool t_type_allowed = true) {
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
SkipWS();
|
SkipWS();
|
||||||
|
|
||||||
@ -701,7 +822,10 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkipWS();
|
SkipWS();
|
||||||
|
|
||||||
|
if (t_type_allowed) {
|
||||||
Id(true);
|
Id(true);
|
||||||
|
}
|
||||||
|
|
||||||
build_match(std::make_shared<eval::Arg_AST_Node>(), prev_stack_top);
|
build_match(std::make_shared<eval::Arg_AST_Node>(), prev_stack_top);
|
||||||
|
|
||||||
@ -1120,6 +1244,32 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads a comma-separated list of values from input. Id's only, no types allowed
|
||||||
|
bool Id_Arg_List() {
|
||||||
|
SkipWS(true);
|
||||||
|
bool retval = false;
|
||||||
|
|
||||||
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
|
|
||||||
|
if (Arg(false)) {
|
||||||
|
retval = true;
|
||||||
|
while (Eol()) {}
|
||||||
|
if (Char(',')) {
|
||||||
|
do {
|
||||||
|
while (Eol()) {}
|
||||||
|
if (!Arg(false)) {
|
||||||
|
throw exception::eval_error("Unexpected value in parameter list", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
} while (Char(','));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
|
||||||
|
|
||||||
|
SkipWS(true);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads a comma-separated list of values from input, for function declarations
|
/// Reads a comma-separated list of values from input, for function declarations
|
||||||
bool Decl_Arg_List() {
|
bool Decl_Arg_List() {
|
||||||
SkipWS(true);
|
SkipWS(true);
|
||||||
@ -1138,8 +1288,8 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
} while (Char(','));
|
} while (Char(','));
|
||||||
}
|
}
|
||||||
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
|
|
||||||
}
|
}
|
||||||
|
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
|
||||||
|
|
||||||
SkipWS(true);
|
SkipWS(true);
|
||||||
|
|
||||||
@ -1223,13 +1373,26 @@ namespace chaiscript
|
|||||||
if (Keyword("fun")) {
|
if (Keyword("fun")) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
|
if (Char('[')) {
|
||||||
|
Id_Arg_List();
|
||||||
|
if (!Char(']')) {
|
||||||
|
throw exception::eval_error("Incomplete anonymous function bind", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// make sure we always have the same number of nodes
|
||||||
|
build_match(std::make_shared<eval::Arg_List_AST_Node>(), prev_stack_top);
|
||||||
|
}
|
||||||
|
|
||||||
if (Char('(')) {
|
if (Char('(')) {
|
||||||
Decl_Arg_List();
|
Decl_Arg_List();
|
||||||
if (!Char(')')) {
|
if (!Char(')')) {
|
||||||
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
|
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
while (Eol()) {}
|
while (Eol()) {}
|
||||||
|
|
||||||
if (!Block()) {
|
if (!Block()) {
|
||||||
@ -1645,6 +1808,10 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename);
|
throw exception::eval_error("Incomplete class block", File_Position(m_line, m_col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_match_stack.size() == prev_stack_top) {
|
||||||
|
m_match_stack.push_back(std::make_shared<eval::Noop_AST_Node>());
|
||||||
|
}
|
||||||
|
|
||||||
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
|
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1665,6 +1832,10 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
|
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_match_stack.size() == prev_stack_top) {
|
||||||
|
m_match_stack.push_back(std::make_shared<eval::Noop_AST_Node>());
|
||||||
|
}
|
||||||
|
|
||||||
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
|
build_match(std::make_shared<eval::Block_AST_Node>(), prev_stack_top);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +40,23 @@ def new(x) {
|
|||||||
eval(type_name(x))();
|
eval(type_name(x))();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def clone(double x) {
|
||||||
|
double(x).copy_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(string x) {
|
||||||
|
string(x).copy_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
def clone(vector x) {
|
||||||
|
vector(x).copy_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def clone(int x) {
|
||||||
|
int(x).copy_var_attrs(x)
|
||||||
|
}
|
||||||
|
|
||||||
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
def clone(x) : function_exists(type_name(x)) && call_exists(eval(type_name(x)), x)
|
||||||
{
|
{
|
||||||
eval(type_name(x))(x).copy_var_attrs(x);
|
eval(type_name(x))(x).copy_var_attrs(x);
|
||||||
|
@ -1,2 +1,6 @@
|
|||||||
auto bob = fun(x) { x + 1 }
|
auto bob = fun(x) { x + 1 }
|
||||||
assert_equal(4, bob(3));
|
assert_equal(4, bob(3));
|
||||||
|
|
||||||
|
var y=3
|
||||||
|
auto bob2 = fun[y](x) { x + y }
|
||||||
|
assert_equal(7, bob2(4))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user