Merge branch 'develop' into method_missing
This commit is contained in:
commit
b67dc4e09a
@ -26,6 +26,14 @@ notifications:
|
||||
- jason@emptycrate.com
|
||||
on_success: 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:
|
||||
global:
|
||||
secure: eiaR6pXiiEpyB8+LLQ1NvZdl0Yylru1BLy9lMoHl+IpUNGGQGywmW/2WAn77rFfmR1OPA2qWQLfgPwgK0HxUA9HHlot9tre5QhiN2Lw8NOT8tCZ6tTm2+QntDBjBGJyal/knRvQkn/6qs6GxlXRerz4ArnnuPL1vESt3zwB0YtU=
|
||||
|
||||
|
||||
|
@ -1,5 +1,16 @@
|
||||
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)
|
||||
|
||||
# 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_VERSION_MAJOR 5)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 6)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 7)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 0)
|
||||
|
||||
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"
|
||||
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"
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -1,103 +1,103 @@
|
||||
# Checks for C++11 features
|
||||
# CXX11_FEATURE_LIST - a list containing all supported features
|
||||
# HAS_CXX11_AUTO - auto keyword
|
||||
# HAS_CXX11_NULLPTR - nullptr
|
||||
# HAS_CXX11_LAMBDA - lambdas
|
||||
# HAS_CXX11_STATIC_ASSERT - static_assert()
|
||||
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
|
||||
# HAS_CXX11_DECLTYPE - decltype keyword
|
||||
# HAS_CXX11_CSTDINT_H - cstdint header
|
||||
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
|
||||
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
|
||||
# HAS_CXX11_CONSTEXPR - constexpr keyword
|
||||
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
|
||||
# HAS_CXX11_FUNC - __func__ preprocessor constant
|
||||
#
|
||||
# Original script by Rolf Eike Beer
|
||||
# Modifications by Andreas Weis
|
||||
#
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
|
||||
|
||||
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
endif()
|
||||
|
||||
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
|
||||
IF (NOT DEFINED ${RESULT_VAR})
|
||||
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
|
||||
|
||||
IF (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
|
||||
ELSE (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
|
||||
ENDIF (${FEATURE_NUMBER})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
|
||||
|
||||
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
|
||||
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
|
||||
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
|
||||
|
||||
IF (CROSS_COMPILING)
|
||||
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ELSE (CROSS_COMPILING)
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}" "${_SRCFILE}")
|
||||
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ENDIF (CROSS_COMPILING)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
|
||||
IF (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ELSE (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ENDIF (_TMP_RESULT)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
|
||||
IF (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
|
||||
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
|
||||
ELSE (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
|
||||
ENDIF (${RESULT_VAR})
|
||||
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
|
||||
ENDIF (NOT DEFINED ${RESULT_VAR})
|
||||
ENDMACRO(CXX11_CHECK_FEATURE)
|
||||
|
||||
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
|
||||
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
|
||||
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
|
||||
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
|
||||
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
|
||||
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
|
||||
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
|
||||
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
|
||||
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
|
||||
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
|
||||
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
|
||||
|
||||
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
|
||||
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
|
||||
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)
|
||||
|
||||
# Checks for C++11 features
|
||||
# CXX11_FEATURE_LIST - a list containing all supported features
|
||||
# HAS_CXX11_AUTO - auto keyword
|
||||
# HAS_CXX11_NULLPTR - nullptr
|
||||
# HAS_CXX11_LAMBDA - lambdas
|
||||
# HAS_CXX11_STATIC_ASSERT - static_assert()
|
||||
# HAS_CXX11_RVALUE_REFERENCES - rvalue references
|
||||
# HAS_CXX11_DECLTYPE - decltype keyword
|
||||
# HAS_CXX11_CSTDINT_H - cstdint header
|
||||
# HAS_CXX11_LONG_LONG - long long signed & unsigned types
|
||||
# HAS_CXX11_VARIADIC_TEMPLATES - variadic templates
|
||||
# HAS_CXX11_CONSTEXPR - constexpr keyword
|
||||
# HAS_CXX11_SIZEOF_MEMBER - sizeof() non-static members
|
||||
# HAS_CXX11_FUNC - __func__ preprocessor constant
|
||||
#
|
||||
# Original script by Rolf Eike Beer
|
||||
# Modifications by Andreas Weis
|
||||
#
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3)
|
||||
|
||||
SET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET(CMAKE_CXX_FLAGS "-std=c++0x")
|
||||
endif()
|
||||
|
||||
MACRO(CXX11_CHECK_FEATURE FEATURE_NAME FEATURE_NUMBER RESULT_VAR)
|
||||
IF (NOT DEFINED ${RESULT_VAR})
|
||||
SET(_bindir "${CMAKE_CURRENT_BINARY_DIR}/cxx11/cxx11_${FEATURE_NAME}")
|
||||
|
||||
IF (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME}-N${FEATURE_NUMBER})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\" (N${FEATURE_NUMBER})")
|
||||
ELSE (${FEATURE_NUMBER})
|
||||
SET(_SRCFILE_BASE ${CMAKE_CURRENT_LIST_DIR}/c++11-test-${FEATURE_NAME})
|
||||
SET(_LOG_NAME "\"${FEATURE_NAME}\"")
|
||||
ENDIF (${FEATURE_NUMBER})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME}")
|
||||
|
||||
SET(_SRCFILE "${_SRCFILE_BASE}.cpp")
|
||||
SET(_SRCFILE_FAIL "${_SRCFILE_BASE}_fail.cpp")
|
||||
SET(_SRCFILE_FAIL_COMPILE "${_SRCFILE_BASE}_fail_compile.cpp")
|
||||
|
||||
IF (CROSS_COMPILING)
|
||||
try_compile(${RESULT_VAR} "${_bindir}" "${_SRCFILE}")
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_compile(${RESULT_VAR} "${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ELSE (CROSS_COMPILING)
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}" "${_SRCFILE}")
|
||||
IF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND NOT _RUN_RESULT_VAR)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
try_run(_RUN_RESULT_VAR _COMPILE_RESULT_VAR
|
||||
"${_bindir}_fail" "${_SRCFILE_FAIL}")
|
||||
IF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ELSE (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ENDIF (_COMPILE_RESULT_VAR AND _RUN_RESULT_VAR)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL})
|
||||
ENDIF (CROSS_COMPILING)
|
||||
IF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
try_compile(_TMP_RESULT "${_bindir}_fail_compile" "${_SRCFILE_FAIL_COMPILE}")
|
||||
IF (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} FALSE)
|
||||
ELSE (_TMP_RESULT)
|
||||
SET(${RESULT_VAR} TRUE)
|
||||
ENDIF (_TMP_RESULT)
|
||||
ENDIF (${RESULT_VAR} AND EXISTS ${_SRCFILE_FAIL_COMPILE})
|
||||
|
||||
IF (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- works")
|
||||
LIST(APPEND CXX11_FEATURE_LIST ${RESULT_VAR})
|
||||
ELSE (${RESULT_VAR})
|
||||
MESSAGE(STATUS "Checking C++11 support for ${_LOG_NAME} -- not supported")
|
||||
ENDIF (${RESULT_VAR})
|
||||
SET(${RESULT_VAR} ${${RESULT_VAR}} CACHE INTERNAL "C++11 support for ${_LOG_NAME}")
|
||||
ENDIF (NOT DEFINED ${RESULT_VAR})
|
||||
ENDMACRO(CXX11_CHECK_FEATURE)
|
||||
|
||||
CXX11_CHECK_FEATURE("auto" 2546 HAS_CXX11_AUTO)
|
||||
CXX11_CHECK_FEATURE("nullptr" 2431 HAS_CXX11_NULLPTR)
|
||||
CXX11_CHECK_FEATURE("lambda" 2927 HAS_CXX11_LAMBDA)
|
||||
CXX11_CHECK_FEATURE("static_assert" 1720 HAS_CXX11_STATIC_ASSERT)
|
||||
CXX11_CHECK_FEATURE("rvalue_references" 2118 HAS_CXX11_RVALUE_REFERENCES)
|
||||
CXX11_CHECK_FEATURE("decltype" 2343 HAS_CXX11_DECLTYPE)
|
||||
CXX11_CHECK_FEATURE("cstdint" "" HAS_CXX11_CSTDINT_H)
|
||||
CXX11_CHECK_FEATURE("long_long" 1811 HAS_CXX11_LONG_LONG)
|
||||
CXX11_CHECK_FEATURE("variadic_templates" 2555 HAS_CXX11_VARIADIC_TEMPLATES)
|
||||
CXX11_CHECK_FEATURE("constexpr" 2235 HAS_CXX11_CONSTEXPR)
|
||||
CXX11_CHECK_FEATURE("sizeof_member" 2253 HAS_CXX11_SIZEOF_MEMBER)
|
||||
CXX11_CHECK_FEATURE("__func__" 2340 HAS_CXX11_FUNC)
|
||||
|
||||
SET(CXX11_FEATURE_LIST ${CXX11_FEATURE_LIST} CACHE STRING "C++11 feature support list")
|
||||
MARK_AS_ADVANCED(FORCE CXX11_FEATURE_LIST)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS ${CHECK_CXX11_OLD_CMAKE_CXX_FLAGS})
|
||||
UNSET(CHECK_CXX11_OLD_CMAKE_CXX_FLAGS)
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!__func__) { return 1; }
|
||||
if(std::strlen(__func__) <= 0) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
if (!__func__) { return 1; }
|
||||
if(std::strlen(__func__) <= 0) { return 1; }
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
auto i = 5;
|
||||
auto f = 3.14159f;
|
||||
auto d = 3.14159;
|
||||
bool ret = (
|
||||
(sizeof(f) < sizeof(d)) &&
|
||||
(sizeof(i) == sizeof(int))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
auto i = 5;
|
||||
auto f = 3.14159f;
|
||||
auto d = 3.14159;
|
||||
bool ret = (
|
||||
(sizeof(f) < sizeof(d)) &&
|
||||
(sizeof(i) == sizeof(int))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
constexpr int square(int x)
|
||||
{
|
||||
return x*x;
|
||||
}
|
||||
|
||||
constexpr int the_answer()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int test_arr[square(3)];
|
||||
bool ret = (
|
||||
(square(the_answer()) == 1764) &&
|
||||
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
constexpr int square(int x)
|
||||
{
|
||||
return x*x;
|
||||
}
|
||||
|
||||
constexpr int the_answer()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int test_arr[square(3)];
|
||||
bool ret = (
|
||||
(square(the_answer()) == 1764) &&
|
||||
(sizeof(test_arr)/sizeof(test_arr[0]) == 9)
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <cstdint>
|
||||
int main()
|
||||
{
|
||||
bool test =
|
||||
(sizeof(int8_t) == 1) &&
|
||||
(sizeof(int16_t) == 2) &&
|
||||
(sizeof(int32_t) == 4) &&
|
||||
(sizeof(int64_t) == 8);
|
||||
return test ? 0 : 1;
|
||||
}
|
||||
#include <cstdint>
|
||||
int main()
|
||||
{
|
||||
bool test =
|
||||
(sizeof(int8_t) == 1) &&
|
||||
(sizeof(int16_t) == 2) &&
|
||||
(sizeof(int32_t) == 4) &&
|
||||
(sizeof(int64_t) == 8);
|
||||
return test ? 0 : 1;
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
|
||||
bool check_size(int i)
|
||||
{
|
||||
return sizeof(int) == sizeof(decltype(i));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = check_size(42);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
||||
bool check_size(int i)
|
||||
{
|
||||
return sizeof(int) == sizeof(decltype(i));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
bool ret = check_size(42);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
return ([&ret]() -> int { return ret; })();
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int ret = 0;
|
||||
return ([&ret]() -> int { return ret; })();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
int main(void)
|
||||
{
|
||||
long long l;
|
||||
unsigned long long ul;
|
||||
|
||||
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
|
||||
}
|
||||
int main(void)
|
||||
{
|
||||
long long l;
|
||||
unsigned long long ul;
|
||||
|
||||
return ((sizeof(l) >= 8) && (sizeof(ul) >= 8)) ? 0 : 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
int* test = nullptr;
|
||||
return test ? 1 : 0;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int* test = nullptr;
|
||||
return test ? 1 : 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
int i = nullptr;
|
||||
return 1;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int i = nullptr;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
int foo(int& lvalue)
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
int foo(int&& rvalue)
|
||||
{
|
||||
return 321;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 42;
|
||||
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
|
||||
}
|
||||
int foo(int& lvalue)
|
||||
{
|
||||
return 123;
|
||||
}
|
||||
|
||||
int foo(int&& rvalue)
|
||||
{
|
||||
return 321;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int i = 42;
|
||||
return ((foo(i) == 123) && (foo(42) == 321)) ? 0 : 1;
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
struct foo {
|
||||
char bar;
|
||||
int baz;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bool ret = (
|
||||
(sizeof(foo::bar) == 1) &&
|
||||
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
|
||||
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
struct foo {
|
||||
char bar;
|
||||
int baz;
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
bool ret = (
|
||||
(sizeof(foo::bar) == 1) &&
|
||||
(sizeof(foo::baz) >= sizeof(foo::bar)) &&
|
||||
(sizeof(foo) >= sizeof(foo::bar)+sizeof(foo::baz))
|
||||
);
|
||||
return ret ? 0 : 1;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(0 < 1, "your ordering of integers is screwed");
|
||||
return 0;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
static_assert(0 < 1, "your ordering of integers is screwed");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
int main()
|
||||
{
|
||||
static_assert(1 < 0, "this should fail");
|
||||
return 0;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
static_assert(1 < 0, "this should fail");
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
int Accumulate()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
int Accumulate(T v, Ts... vs)
|
||||
{
|
||||
return v + Accumulate(vs...);
|
||||
}
|
||||
|
||||
template<int... Is>
|
||||
int CountElements()
|
||||
{
|
||||
return sizeof...(Is);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int acc = Accumulate(1, 2, 3, 4, -5);
|
||||
int count = CountElements<1,2,3,4,5>();
|
||||
return ((acc == 5) && (count == 5)) ? 0 : 1;
|
||||
}
|
||||
int Accumulate()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename... Ts>
|
||||
int Accumulate(T v, Ts... vs)
|
||||
{
|
||||
return v + Accumulate(vs...);
|
||||
}
|
||||
|
||||
template<int... Is>
|
||||
int CountElements()
|
||||
{
|
||||
return sizeof...(Is);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
int acc = Accumulate(1, 2, 3, 4, -5);
|
||||
int count = CountElements<1,2,3,4,5>();
|
||||
return ((acc == 5) && (count == 5)) ? 0 : 1;
|
||||
}
|
||||
|
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
|
||||
#define CHAISCRIPT_MSVC _MSC_VER
|
||||
#define CHAISCRIPT_HAS_DECLSPEC
|
||||
#if _MSC_VER <= 1800
|
||||
#define CHAISCRIPT_MSVC_12
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
@ -45,7 +48,7 @@
|
||||
|
||||
namespace chaiscript {
|
||||
static const int version_major = 5;
|
||||
static const int version_minor = 6;
|
||||
static const int version_minor = 7;
|
||||
static const int version_patch = 0;
|
||||
}
|
||||
|
||||
|
@ -158,7 +158,7 @@ namespace chaiscript
|
||||
|
||||
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));
|
||||
|
||||
|
@ -303,7 +303,7 @@ namespace chaiscript
|
||||
ModulePtr sequence_type(const std::string &/*type*/, ModulePtr m = ModulePtr(new Module()))
|
||||
{
|
||||
m->add(fun(&detail::insert_at<ContainerType>),
|
||||
[](){
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
return "insert_ref_at";
|
||||
} else {
|
||||
@ -329,7 +329,7 @@ namespace chaiscript
|
||||
|
||||
typedef void (ContainerType::*push_back)(const typename ContainerType::value_type &);
|
||||
m->add(fun(static_cast<push_back>(&ContainerType::push_back)),
|
||||
[](){
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
@ -357,7 +357,7 @@ namespace chaiscript
|
||||
m->add(fun(static_cast<constfrontptr>(&ContainerType::front)), "front");
|
||||
|
||||
m->add(fun(static_cast<pushptr>(&ContainerType::push_front)),
|
||||
[](){
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::value_type) == typeid(Boxed_Value)) {
|
||||
return "push_front_ref";
|
||||
} else {
|
||||
@ -418,7 +418,7 @@ namespace chaiscript
|
||||
m->add(fun(&detail::insert<ContainerType>), "insert");
|
||||
|
||||
m->add(fun(&detail::insert_ref<ContainerType>),
|
||||
[](){
|
||||
[]()->std::string{
|
||||
if (typeid(typename ContainerType::mapped_type) == typeid(Boxed_Value)) {
|
||||
return "insert_ref";
|
||||
} else {
|
||||
@ -538,7 +538,7 @@ namespace chaiscript
|
||||
|
||||
//Special case: add push_back to string (which doesn't support other back_insertion operations
|
||||
m->add(fun(&String::push_back),
|
||||
[](){
|
||||
[]()->std::string{
|
||||
if (typeid(typename String::value_type) == typeid(Boxed_Value)) {
|
||||
return "push_back_ref";
|
||||
} else {
|
||||
|
@ -74,46 +74,47 @@ namespace chaiscript
|
||||
template<typename Type>
|
||||
typename detail::Cast_Helper<Type>::Result_Type boxed_cast(const Boxed_Value &bv, const Type_Conversions *t_conversions = nullptr)
|
||||
{
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
if (!t_conversions || bv.get_type_info().bare_equal(user_type<Type>()) || (t_conversions && !t_conversions->convertable_type<Type>())) {
|
||||
try {
|
||||
return detail::Cast_Helper<Type>::cast(bv, t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
//Thank you MSVC, yes we know that a constant value is being used in the if
|
||||
// statment in THIS VERSION of the template instantiation
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
|
||||
if (t_conversions && t_conversions->convertable_type<Type>())
|
||||
{
|
||||
if (t_conversions && t_conversions->convertable_type<Type>())
|
||||
{
|
||||
try {
|
||||
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
|
||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
|
||||
} catch (...) {
|
||||
try {
|
||||
// std::cout << "trying an up conversion " << typeid(Type).name() << '\n';
|
||||
// We will not catch any bad_boxed_dynamic_cast that is thrown, let the user get it
|
||||
// either way, we are not responsible if it doesn't work
|
||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_conversion<Type>(bv), t_conversions);
|
||||
} catch (...) {
|
||||
try {
|
||||
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
|
||||
// try going the other way - down the inheritance graph
|
||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
// std::cout << "trying a down conversion " << typeid(Type).name() << '\n';
|
||||
// try going the other way - down the inheritance graph
|
||||
return detail::Cast_Helper<Type>::cast(t_conversions->boxed_type_down_conversion<Type>(bv), t_conversions);
|
||||
} catch (const chaiscript::detail::exception::bad_any_cast &) {
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
} else {
|
||||
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
} else {
|
||||
// If it's not polymorphic, just throw the error, don't waste the time on the
|
||||
// attempted dynamic_cast
|
||||
throw exception::bad_boxed_cast(bv.get_type_info(), typeid(Type));
|
||||
}
|
||||
|
||||
#ifdef CHAISCRIPT_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -641,6 +641,7 @@ namespace chaiscript
|
||||
/// \throws std::range_error if it does not
|
||||
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);
|
||||
|
||||
const auto &funs = get_function_objects_int();
|
||||
|
@ -30,7 +30,7 @@ namespace chaiscript
|
||||
Proxy_Function build_constructor_(Class (*)(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)
|
||||
{
|
||||
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 {
|
||||
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
|
||||
{
|
||||
const auto &types = get_param_types();
|
||||
|
||||
if (types.size() < 2)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return compare_type_to_param(types[1], bv, t_conversions);
|
||||
return compare_type_to_param(m_types[1], bv, t_conversions);
|
||||
}
|
||||
|
||||
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,
|
||||
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;
|
||||
|
||||
for (const auto &func : funcs)
|
||||
@ -808,11 +803,17 @@ namespace chaiscript
|
||||
for (const auto &func : ordered_funcs )
|
||||
{
|
||||
try {
|
||||
if (func.second->filter(plist, t_conversions))
|
||||
if (func.first == 0 || func.second->filter(plist, t_conversions))
|
||||
{
|
||||
return (*(func.second))(plist, t_conversions);
|
||||
}
|
||||
} 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
|
||||
} catch (const exception::arity_error &) {
|
||||
//invalid num params, try again
|
||||
|
@ -40,17 +40,25 @@ namespace chaiscript
|
||||
template<typename Ret, typename Class, typename ... 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
|
||||
/// std::function for member function pointers seems to be broken in MSVC
|
||||
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>
|
||||
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
|
||||
/// 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>
|
||||
@ -61,7 +69,7 @@ namespace chaiscript
|
||||
{
|
||||
/// \todo is it possible to reduce the number of templates generated here?
|
||||
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>
|
||||
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:
|
||||
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) :
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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) {}
|
||||
|
||||
virtual ~AST_Node() {}
|
||||
@ -495,7 +495,6 @@ namespace chaiscript
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Special type for returned values
|
||||
struct Return_Value {
|
||||
Boxed_Value retval;
|
||||
|
@ -276,7 +276,7 @@ namespace chaiscript
|
||||
parser::ChaiScript_Parser parser;
|
||||
if (parser.parse(t_input, t_filename)) {
|
||||
//parser.show_match_stack();
|
||||
return parser.ast()->eval(m_engine);
|
||||
return parser.optimized_ast()->eval(m_engine);
|
||||
} else {
|
||||
return Boxed_Value();
|
||||
}
|
||||
|
@ -47,9 +47,13 @@ namespace chaiscript
|
||||
namespace detail
|
||||
{
|
||||
/// 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);
|
||||
|
||||
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) {
|
||||
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 {
|
||||
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) :
|
||||
@ -222,14 +227,13 @@ namespace chaiscript
|
||||
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;
|
||||
|
||||
if ((this->children.size() > 1)) {
|
||||
const AST_Node &first_child(*(this->children[1]));
|
||||
if (first_child.identifier == AST_Node_Type::Arg_List) {
|
||||
for (const auto &child : first_child.children) {
|
||||
params.push_back(child->eval(t_ss));
|
||||
}
|
||||
params.reserve(this->children[1]->children.size());
|
||||
for (const auto &child : this->children[1]->children) {
|
||||
params.push_back(child->eval(t_ss));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
struct Inplace_Fun_Call_AST_Node : public AST_Node {
|
||||
public:
|
||||
@ -446,26 +540,28 @@ namespace chaiscript
|
||||
struct Equation_AST_Node : public AST_Node {
|
||||
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) :
|
||||
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 Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE {
|
||||
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);
|
||||
|
||||
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())
|
||||
{
|
||||
try {
|
||||
return Boxed_Number::do_oper(oper, lhs, rhs);
|
||||
return Boxed_Number::do_oper(m_oper, lhs, rhs);
|
||||
} catch (const std::exception &) {
|
||||
throw exception::eval_error("Error with unsupported arithmetic assignment operation");
|
||||
}
|
||||
} else if (oper == Operators::assign) {
|
||||
} else if (m_oper == Operators::assign) {
|
||||
try {
|
||||
if (lhs.is_undef()) {
|
||||
if (!this->children.empty() &&
|
||||
@ -701,28 +797,31 @@ namespace chaiscript
|
||||
virtual ~Lambda_AST_Node() {}
|
||||
|
||||
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;
|
||||
for (const auto &capture : children[0]->children) {
|
||||
named_captures.insert(std::make_pair(capture->children[0]->text, capture->children[0]->eval(t_ss)));
|
||||
}
|
||||
return named_captures;
|
||||
}();
|
||||
|
||||
if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) {
|
||||
numparams = this->children[0]->children.size();
|
||||
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);
|
||||
}
|
||||
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();
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
struct Block_AST_Node : public AST_Node {
|
||||
@ -732,25 +831,14 @@ namespace chaiscript
|
||||
virtual ~Block_AST_Node() {}
|
||||
|
||||
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);
|
||||
|
||||
for (size_t i = 0; i < num_children; ++i) {
|
||||
try {
|
||||
if (i + 1 < num_children)
|
||||
{
|
||||
this->children[i]->eval(t_ss);
|
||||
} else {
|
||||
return this->children[i]->eval(t_ss);
|
||||
}
|
||||
}
|
||||
catch (const chaiscript::eval::detail::Return_Value &) {
|
||||
throw;
|
||||
}
|
||||
const auto num_children = children.size();
|
||||
for (size_t i = 0; i < num_children-1; ++i) {
|
||||
children[i]->eval(t_ss);
|
||||
}
|
||||
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))) {
|
||||
return this->children[1]->eval(t_ss);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (this->children.size() > 2) {
|
||||
size_t i = 2;
|
||||
bool cond = false;
|
||||
@ -917,26 +1004,22 @@ namespace chaiscript
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
// initial expression
|
||||
this->children[0]->eval(t_ss);
|
||||
|
||||
try {
|
||||
// while condition evals to true
|
||||
while (get_bool_condition(this->children[1]->eval(t_ss))) {
|
||||
for (
|
||||
children[0]->eval(t_ss);
|
||||
get_bool_condition(children[1]->eval(t_ss));
|
||||
children[2]->eval(t_ss)
|
||||
) {
|
||||
try {
|
||||
// Body of Loop
|
||||
this->children[3]->eval(t_ss);
|
||||
children[3]->eval(t_ss);
|
||||
} catch (detail::Continue_Loop &) {
|
||||
// we got a continue exception, which means all of the remaining
|
||||
// loop implementation is skipped and we just need to continue to
|
||||
// the next iteration step
|
||||
}
|
||||
|
||||
// loop expression
|
||||
this->children[2]->eval(t_ss);
|
||||
}
|
||||
}
|
||||
catch (detail::Break_Loop &) {
|
||||
} catch (detail::Break_Loop &) {
|
||||
// loop broken
|
||||
}
|
||||
|
||||
@ -1388,7 +1471,7 @@ namespace chaiscript
|
||||
guard = std::make_shared<dispatch::Dynamic_Proxy_Function>
|
||||
(std::bind(chaiscript::eval::detail::eval_function,
|
||||
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 {
|
||||
@ -1399,7 +1482,7 @@ namespace chaiscript
|
||||
if (function_name == class_name) {
|
||||
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,
|
||||
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)),
|
||||
function_name);
|
||||
|
||||
@ -1415,7 +1498,7 @@ namespace chaiscript
|
||||
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::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);
|
||||
} catch (const std::range_error &) {
|
||||
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::Dynamic_Proxy_Function>(std::bind(chaiscript::eval::detail::eval_function,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -196,6 +196,127 @@ namespace chaiscript
|
||||
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
|
||||
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;
|
||||
@ -692,7 +813,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Reads an argument from input
|
||||
bool Arg() {
|
||||
bool Arg(const bool t_type_allowed = true) {
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
SkipWS();
|
||||
|
||||
@ -701,7 +822,10 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
SkipWS();
|
||||
Id(true);
|
||||
|
||||
if (t_type_allowed) {
|
||||
Id(true);
|
||||
}
|
||||
|
||||
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
|
||||
bool Decl_Arg_List() {
|
||||
SkipWS(true);
|
||||
@ -1138,8 +1288,8 @@ namespace chaiscript
|
||||
}
|
||||
} 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);
|
||||
|
||||
@ -1223,13 +1373,26 @@ namespace chaiscript
|
||||
if (Keyword("fun")) {
|
||||
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('(')) {
|
||||
Decl_Arg_List();
|
||||
if (!Char(')')) {
|
||||
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()) {}
|
||||
|
||||
if (!Block()) {
|
||||
@ -1645,6 +1808,10 @@ namespace chaiscript
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1665,6 +1832,10 @@ namespace chaiscript
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,24 @@ def eq(l, r) {
|
||||
|
||||
def new(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)
|
||||
{
|
||||
|
@ -1,2 +1,6 @@
|
||||
auto bob = fun(x) { x + 1 }
|
||||
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