Merge remote-tracking branch 'origin/OptionalTypedArgs' into develop
This commit is contained in:
@@ -19,7 +19,6 @@
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_info.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
@@ -62,217 +61,6 @@ namespace chaiscript
|
||||
std::map<std::string, Boxed_Value> m_attrs;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
/// A Proxy_Function implementation designed for calling a function
|
||||
/// that is automatically guarded based on the first param based on the
|
||||
/// param's type name
|
||||
class Dynamic_Object_Function : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const Type_Info &t_ti)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Function() {}
|
||||
|
||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||
{
|
||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return m_func->call_match(vals, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return (*m_func)(params, t_conversions);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_types(
|
||||
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||
{
|
||||
std::vector<Type_Info> types(t_inner_types);
|
||||
|
||||
assert(types.size() > 1);
|
||||
assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
std::unique_ptr<Type_Info> m_ti;
|
||||
const Type_Info m_doti;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation designed for creating a new
|
||||
* Dynamic_Object
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Constructor : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Constructor(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
|
||||
{
|
||||
auto begin = tl.begin();
|
||||
auto end = tl.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Constructor() {}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
if (dc)
|
||||
{
|
||||
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||
|
||||
return m_func->call_match(new_vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
auto bv = var(Dynamic_Object(m_type_name));
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params, t_conversions);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
251
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
251
include/chaiscript/dispatchkit/dynamic_object_detail.hpp
Normal file
@@ -0,0 +1,251 @@
|
||||
// This file is distributed under the BSD License.
|
||||
// See "license.txt" for details.
|
||||
// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com)
|
||||
// Copyright 2009-2014, Jason Turner (jason@emptycrate.com)
|
||||
// http://www.chaiscript.com
|
||||
|
||||
#ifndef CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
#define CHAISCRIPT_DYNAMIC_OBJECT_DETAIL_HPP_
|
||||
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "../chaiscript_defines.hpp"
|
||||
#include "boxed_cast.hpp"
|
||||
#include "boxed_cast_helper.hpp"
|
||||
#include "boxed_value.hpp"
|
||||
#include "proxy_functions.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
namespace dispatch {
|
||||
class Proxy_Function_Base;
|
||||
} // namespace dispatch
|
||||
} // namespace chaiscript
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// A Proxy_Function implementation designed for calling a function
|
||||
/// that is automatically guarded based on the first param based on the
|
||||
/// param's type name
|
||||
class Dynamic_Object_Function : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(t_func->get_param_types(), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
Dynamic_Object_Function(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func,
|
||||
const Type_Info &t_ti)
|
||||
: Proxy_Function_Base(build_param_types(t_func->get_param_types(), t_ti), t_func->get_arity()),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func), m_ti(new Type_Info(t_ti)), m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Function() {}
|
||||
|
||||
Dynamic_Object_Function &operator=(const Dynamic_Object_Function) = delete;
|
||||
Dynamic_Object_Function(Dynamic_Object_Function &) = delete;
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (const auto *df = dynamic_cast<const Dynamic_Object_Function *>(&f))
|
||||
{
|
||||
return df->m_type_name == m_type_name && (*df->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(vals, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return m_func->call_match(vals, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual std::vector<Const_Proxy_Function> get_contained_functions() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return {m_func};
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
if (dynamic_object_typename_match(params, m_type_name, m_ti, t_conversions))
|
||||
{
|
||||
return (*m_func)(params, t_conversions);
|
||||
} else {
|
||||
throw exception::guard_error();
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool compare_first_type(const Boxed_Value &bv, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return dynamic_object_typename_match(bv, m_type_name, m_ti, t_conversions);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::vector<Type_Info> build_param_types(
|
||||
const std::vector<Type_Info> &t_inner_types, const Type_Info& t_objectti)
|
||||
{
|
||||
std::vector<Type_Info> types(t_inner_types);
|
||||
|
||||
assert(types.size() > 1);
|
||||
//assert(types[1].bare_equal(user_type<Boxed_Value>()));
|
||||
types[1] = t_objectti;
|
||||
return types;
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const Boxed_Value &bv, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (ti)
|
||||
{
|
||||
return bv.get_type_info().bare_equal(*ti);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool dynamic_object_typename_match(const std::vector<Boxed_Value> &bvs, const std::string &name,
|
||||
const std::unique_ptr<Type_Info> &ti, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (bvs.size() > 0)
|
||||
{
|
||||
return dynamic_object_typename_match(bvs[0], name, ti, t_conversions);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
std::unique_ptr<Type_Info> m_ti;
|
||||
const Type_Info m_doti;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A Proxy_Function implementation designed for creating a new
|
||||
* Dynamic_Object
|
||||
* that is automatically guarded based on the first param based on the
|
||||
* param's type name
|
||||
*/
|
||||
class Dynamic_Object_Constructor : public Proxy_Function_Base
|
||||
{
|
||||
public:
|
||||
Dynamic_Object_Constructor(
|
||||
std::string t_type_name,
|
||||
const Proxy_Function &t_func)
|
||||
: Proxy_Function_Base(build_type_list(t_func->get_param_types()), t_func->get_arity() - 1),
|
||||
m_type_name(std::move(t_type_name)), m_func(t_func)
|
||||
{
|
||||
assert( (t_func->get_arity() > 0 || t_func->get_arity() < 0)
|
||||
&& "Programming error, Dynamic_Object_Function must have at least one parameter (this)");
|
||||
}
|
||||
|
||||
static std::vector<Type_Info> build_type_list(const std::vector<Type_Info> &tl)
|
||||
{
|
||||
auto begin = tl.begin();
|
||||
auto end = tl.end();
|
||||
|
||||
if (begin != end)
|
||||
{
|
||||
++begin;
|
||||
}
|
||||
|
||||
return std::vector<Type_Info>(begin, end);
|
||||
}
|
||||
|
||||
virtual ~Dynamic_Object_Constructor() {}
|
||||
|
||||
virtual bool operator==(const Proxy_Function_Base &f) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
const Dynamic_Object_Constructor *dc = dynamic_cast<const Dynamic_Object_Constructor*>(&f);
|
||||
if (dc)
|
||||
{
|
||||
return dc->m_type_name == m_type_name && (*dc->m_func) == (*m_func);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
std::vector<Boxed_Value> new_vals{Boxed_Value(Dynamic_Object(m_type_name))};
|
||||
new_vals.insert(new_vals.end(), vals.begin(), vals.end());
|
||||
|
||||
return m_func->call_match(new_vals, t_conversions);
|
||||
}
|
||||
|
||||
virtual std::string annotation() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return m_func->annotation();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual Boxed_Value do_call(const std::vector<Boxed_Value> ¶ms, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
auto bv = var(Dynamic_Object(m_type_name));
|
||||
std::vector<Boxed_Value> new_params{bv};
|
||||
new_params.insert(new_params.end(), params.begin(), params.end());
|
||||
|
||||
(*m_func)(new_params, t_conversions);
|
||||
|
||||
return bv;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_type_name;
|
||||
Proxy_Function m_func;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@@ -8,6 +8,8 @@
|
||||
#ifndef CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
#define CHAISCRIPT_PROXY_CONSTRUCTORS_HPP_
|
||||
|
||||
#include "proxy_functions.hpp"
|
||||
|
||||
namespace chaiscript
|
||||
{
|
||||
namespace dispatch
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "boxed_value.hpp"
|
||||
#include "proxy_functions_detail.hpp"
|
||||
#include "type_info.hpp"
|
||||
#include "dynamic_object.hpp"
|
||||
|
||||
namespace chaiscript {
|
||||
class Type_Conversions;
|
||||
@@ -42,6 +43,95 @@ namespace chaiscript
|
||||
|
||||
namespace dispatch
|
||||
{
|
||||
class Param_Types
|
||||
{
|
||||
public:
|
||||
Param_Types()
|
||||
: m_has_types(false),
|
||||
m_doti(user_type<Dynamic_Object>())
|
||||
{}
|
||||
|
||||
Param_Types(std::vector<std::pair<std::string, Type_Info>> t_types)
|
||||
: m_types(std::move(t_types)),
|
||||
m_has_types(false),
|
||||
m_doti(user_type<Dynamic_Object>())
|
||||
{
|
||||
update_has_types();
|
||||
}
|
||||
|
||||
void push_front(std::string t_name, Type_Info t_ti)
|
||||
{
|
||||
m_types.emplace(m_types.begin(), std::move(t_name), std::move(t_ti));
|
||||
update_has_types();
|
||||
}
|
||||
|
||||
bool operator==(const Param_Types &t_rhs) const
|
||||
{
|
||||
return m_types == t_rhs.m_types;
|
||||
}
|
||||
|
||||
bool match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const
|
||||
{
|
||||
if (!m_has_types) return true;
|
||||
if (vals.size() != m_types.size()) return false;
|
||||
|
||||
for (size_t i = 0; i < vals.size(); ++i)
|
||||
{
|
||||
const auto &name = m_types[i].first;
|
||||
if (!name.empty()) {
|
||||
const auto &bv = vals[i];
|
||||
|
||||
if (bv.get_type_info().bare_equal(m_doti))
|
||||
{
|
||||
try {
|
||||
const Dynamic_Object &d = boxed_cast<const Dynamic_Object &>(bv, &t_conversions);
|
||||
return name == "Dynamic_Object" || d.get_type_name() == name;
|
||||
} catch (const std::bad_cast &) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const auto &ti = m_types[i].second;
|
||||
if (!ti.is_undef())
|
||||
{
|
||||
if (!bv.get_type_info().bare_equal(ti)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, Type_Info>> &types() const
|
||||
{
|
||||
return m_types;
|
||||
}
|
||||
|
||||
private:
|
||||
void update_has_types()
|
||||
{
|
||||
for (const auto &type : m_types)
|
||||
{
|
||||
if (!type.first.empty())
|
||||
{
|
||||
m_has_types = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_has_types = false;
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, Type_Info>> m_types;
|
||||
bool m_has_types;
|
||||
Type_Info m_doti;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Pure virtual base class for all Proxy_Function implementations
|
||||
* Proxy_Functions are a type erasure of type safe C++
|
||||
@@ -215,10 +305,12 @@ namespace chaiscript
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> t_f,
|
||||
int t_arity=-1,
|
||||
AST_NodePtr t_parsenode = AST_NodePtr(),
|
||||
Param_Types t_param_types = Param_Types(),
|
||||
std::string t_description = "",
|
||||
Proxy_Function t_guard = Proxy_Function())
|
||||
: Proxy_Function_Base(build_param_type_list(t_arity), t_arity),
|
||||
m_f(std::move(t_f)), m_arity(t_arity), m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
||||
: Proxy_Function_Base(build_param_type_list(t_param_types), t_arity),
|
||||
m_f(std::move(t_f)), m_arity(t_arity), m_param_types(std::move(t_param_types)),
|
||||
m_description(std::move(t_description)), m_guard(std::move(t_guard)), m_parsenode(std::move(t_parsenode))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -231,14 +323,15 @@ namespace chaiscript
|
||||
return this == &rhs
|
||||
|| (prhs
|
||||
&& this->m_arity == prhs->m_arity
|
||||
&& !this->m_guard && !prhs->m_guard);
|
||||
&& !this->m_guard && !prhs->m_guard
|
||||
&& this->m_param_types == prhs->m_param_types);
|
||||
}
|
||||
|
||||
virtual bool call_match(const std::vector<Boxed_Value> &vals, const Type_Conversions &t_conversions) const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
return (m_arity < 0 || vals.size() == size_t(m_arity))
|
||||
return (m_arity < 0 || (vals.size() == size_t(m_arity) && m_param_types.match(vals, t_conversions)))
|
||||
&& test_guard(vals, t_conversions);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Proxy_Function get_guard() const
|
||||
@@ -261,8 +354,7 @@ namespace chaiscript
|
||||
{
|
||||
if (m_arity < 0 || params.size() == size_t(m_arity))
|
||||
{
|
||||
|
||||
if (test_guard(params, t_conversions))
|
||||
if (call_match(params, t_conversions) && test_guard(params, t_conversions))
|
||||
{
|
||||
return m_f(params);
|
||||
} else {
|
||||
@@ -291,18 +383,19 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<Type_Info> build_param_type_list(int arity)
|
||||
static std::vector<Type_Info> build_param_type_list(const Param_Types &t_types)
|
||||
{
|
||||
std::vector<Type_Info> types;
|
||||
|
||||
// For the return type
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
|
||||
if (arity > 0)
|
||||
for (const auto &t : t_types.types())
|
||||
{
|
||||
for (int i = 0; i < arity; ++i)
|
||||
{
|
||||
if (t.second.is_undef()) {
|
||||
types.push_back(chaiscript::detail::Get_Type_Info<Boxed_Value>::get());
|
||||
} else {
|
||||
types.push_back(t.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,6 +404,7 @@ namespace chaiscript
|
||||
|
||||
std::function<Boxed_Value (const std::vector<Boxed_Value> &)> m_f;
|
||||
int m_arity;
|
||||
Param_Types m_param_types;
|
||||
std::string m_description;
|
||||
Proxy_Function m_guard;
|
||||
AST_NodePtr m_parsenode;
|
||||
|
@@ -37,7 +37,7 @@ namespace chaiscript
|
||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Continue, Map_Pair, Value_Range,
|
||||
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary
|
||||
Logical_And, Logical_Or, Reference, Switch, Case, Default, Ternary_Cond, Noop, Class, Binary, Arg
|
||||
};
|
||||
};
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace chaiscript
|
||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Continue", "Map_Pair", "Value_Range",
|
||||
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary"};
|
||||
"Logical_And", "Logical_Or", "Reference", "Switch", "Case", "Default", "Ternary Condition", "Noop", "Class", "Binary", "Arg"};
|
||||
|
||||
return ast_node_types[ast_node_type];
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include "../dispatchkit/boxed_number.hpp"
|
||||
#include "../dispatchkit/boxed_value.hpp"
|
||||
#include "../dispatchkit/dispatchkit.hpp"
|
||||
#include "../dispatchkit/dynamic_object_detail.hpp"
|
||||
#include "../dispatchkit/proxy_functions.hpp"
|
||||
#include "../dispatchkit/proxy_functions_detail.hpp"
|
||||
#include "../dispatchkit/register_function.hpp"
|
||||
@@ -351,6 +352,28 @@ namespace chaiscript
|
||||
|
||||
};
|
||||
|
||||
struct Arg_AST_Node : public AST_Node {
|
||||
public:
|
||||
Arg_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::Arg_List, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Arg_AST_Node() {}
|
||||
|
||||
virtual std::string pretty_print() const CHAISCRIPT_OVERRIDE
|
||||
{
|
||||
std::ostringstream oss;
|
||||
for (size_t j = 0; j < this->children.size(); ++j) {
|
||||
if (j != 0)
|
||||
{
|
||||
oss << " ";
|
||||
}
|
||||
|
||||
oss << this->children[j]->pretty_print();
|
||||
}
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct Arg_List_AST_Node : public AST_Node {
|
||||
public:
|
||||
Arg_List_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) :
|
||||
@@ -371,6 +394,53 @@ namespace chaiscript
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
static std::string get_arg_name(const AST_NodePtr &t_node) {
|
||||
if (t_node->children.empty())
|
||||
{
|
||||
return t_node->text;
|
||||
} else if (t_node->children.size() == 1) {
|
||||
return t_node->children[0]->text;
|
||||
} else {
|
||||
return t_node->children[1]->text;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> get_arg_names(const AST_NodePtr &t_node) {
|
||||
std::vector<std::string> retval;
|
||||
|
||||
for (const auto &node : t_node->children)
|
||||
{
|
||||
retval.push_back(get_arg_name(node));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static std::pair<std::string, Type_Info> get_arg_type(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss)
|
||||
{
|
||||
if (t_node->children.size() < 2)
|
||||
{
|
||||
return std::pair<std::string, Type_Info>();
|
||||
} else {
|
||||
try {
|
||||
return std::pair<std::string, Type_Info>(t_node->children[0]->text, t_ss.get_type(t_node->children[0]->text));
|
||||
} catch (const std::range_error &) {
|
||||
return std::pair<std::string, Type_Info>(t_node->children[0]->text, Type_Info());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static dispatch::Param_Types get_arg_types(const AST_NodePtr &t_node, chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||
std::vector<std::pair<std::string, Type_Info>> retval;
|
||||
|
||||
for (const auto &child : t_node->children)
|
||||
{
|
||||
retval.push_back(get_arg_type(child, t_ss));
|
||||
}
|
||||
|
||||
return dispatch::Param_Types(std::move(retval));
|
||||
}
|
||||
};
|
||||
|
||||
struct Equation_AST_Node : public AST_Node {
|
||||
@@ -638,13 +708,12 @@ namespace chaiscript
|
||||
|
||||
size_t numparams = 0;
|
||||
|
||||
dispatch::Param_Types param_types;
|
||||
|
||||
if (!this->children.empty() && (this->children[0]->identifier == AST_Node_Type::Arg_List)) {
|
||||
numparams = this->children[0]->children.size();
|
||||
|
||||
for (const auto &child : this->children[0]->children)
|
||||
{
|
||||
t_param_names.push_back(child->text);
|
||||
}
|
||||
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 &lambda_node = this->children.back();
|
||||
@@ -654,7 +723,7 @@ namespace chaiscript
|
||||
{
|
||||
return detail::eval_function(t_ss, lambda_node, t_param_names, t_params);
|
||||
},
|
||||
static_cast<int>(numparams), lambda_node)));
|
||||
static_cast<int>(numparams), lambda_node, param_types)));
|
||||
}
|
||||
|
||||
};
|
||||
@@ -698,13 +767,12 @@ namespace chaiscript
|
||||
size_t numparams = 0;
|
||||
AST_NodePtr guardnode;
|
||||
|
||||
dispatch::Param_Types param_types;
|
||||
|
||||
if ((this->children.size() > 2) && (this->children[1]->identifier == AST_Node_Type::Arg_List)) {
|
||||
numparams = this->children[1]->children.size();
|
||||
|
||||
for (const auto &child : this->children[1]->children)
|
||||
{
|
||||
t_param_names.push_back(child->text);
|
||||
}
|
||||
t_param_names = Arg_List_AST_Node::get_arg_names(this->children[1]);
|
||||
param_types = Arg_List_AST_Node::get_arg_types(this->children[1], t_ss);
|
||||
|
||||
if (this->children.size() > 3) {
|
||||
guardnode = this->children[2];
|
||||
@@ -737,7 +805,7 @@ namespace chaiscript
|
||||
{
|
||||
return detail::eval_function(t_ss, func_node, t_param_names, t_params);
|
||||
}, static_cast<int>(numparams), this->children.back(),
|
||||
l_annotation, guard)), l_function_name);
|
||||
param_types, l_annotation, guard)), l_function_name);
|
||||
}
|
||||
catch (const exception::reserved_word_error &e) {
|
||||
throw exception::eval_error("Reserved word used as function name '" + e.word() + "'");
|
||||
@@ -1188,11 +1256,74 @@ namespace chaiscript
|
||||
Try_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) :
|
||||
AST_Node(t_ast_node_text, AST_Node_Type::Try, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||
virtual ~Try_AST_Node() {}
|
||||
|
||||
Boxed_Value handle_exception(chaiscript::detail::Dispatch_Engine &t_ss, const Boxed_Value &t_except) const
|
||||
{
|
||||
Boxed_Value retval;
|
||||
|
||||
size_t end_point = this->children.size();
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
assert(end_point > 0);
|
||||
end_point = this->children.size() - 1;
|
||||
}
|
||||
for (size_t i = 1; i < end_point; ++i) {
|
||||
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
||||
AST_NodePtr catch_block = this->children[i];
|
||||
|
||||
if (catch_block->children.size() == 1) {
|
||||
//No variable capture, no guards
|
||||
retval = catch_block->children[0]->eval(t_ss);
|
||||
break;
|
||||
} else if (catch_block->children.size() == 2 || catch_block->children.size() == 3) {
|
||||
const auto name = Arg_List_AST_Node::get_arg_name(catch_block->children[0]);
|
||||
|
||||
if (dispatch::Param_Types(
|
||||
std::vector<std::pair<std::string, Type_Info>>{Arg_List_AST_Node::get_arg_type(catch_block->children[0], t_ss)}
|
||||
).match(std::vector<Boxed_Value>{t_except}, t_ss.conversions()))
|
||||
{
|
||||
t_ss.add_object(name, t_except);
|
||||
|
||||
if (catch_block->children.size() == 2) {
|
||||
//Variable capture, no guards
|
||||
retval = catch_block->children[1]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
else if (catch_block->children.size() == 3) {
|
||||
//Variable capture, guards
|
||||
|
||||
bool guard = false;
|
||||
try {
|
||||
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Guard condition not boolean");
|
||||
}
|
||||
if (guard) {
|
||||
retval = catch_block->children[2]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Internal error: catch block size unrecognized");
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) const CHAISCRIPT_OVERRIDE{
|
||||
Boxed_Value retval;
|
||||
|
||||
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||
|
||||
|
||||
try {
|
||||
retval = this->children[0]->eval(t_ss);
|
||||
}
|
||||
@@ -1203,98 +1334,11 @@ namespace chaiscript
|
||||
throw;
|
||||
}
|
||||
catch (const std::exception &e) {
|
||||
Boxed_Value except(std::ref(e));
|
||||
retval = handle_exception(t_ss, Boxed_Value(std::ref(e)));
|
||||
|
||||
size_t end_point = this->children.size();
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
assert(end_point > 0);
|
||||
end_point = this->children.size() - 1;
|
||||
}
|
||||
for (size_t i = 1; i < end_point; ++i) {
|
||||
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
||||
AST_NodePtr catch_block = this->children[i];
|
||||
|
||||
if (catch_block->children.size() == 1) {
|
||||
//No variable capture, no guards
|
||||
retval = catch_block->children[0]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
else if (catch_block->children.size() == 2) {
|
||||
//Variable capture, no guards
|
||||
t_ss.add_object(catch_block->children[0]->text, except);
|
||||
retval = catch_block->children[1]->eval(t_ss);
|
||||
|
||||
break;
|
||||
}
|
||||
else if (catch_block->children.size() == 3) {
|
||||
//Variable capture, no guards
|
||||
t_ss.add_object(catch_block->children[0]->text, except);
|
||||
|
||||
bool guard = false;
|
||||
try {
|
||||
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
|
||||
} catch (const exception::bad_boxed_cast &) {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Guard condition not boolean");
|
||||
}
|
||||
if (guard) {
|
||||
retval = catch_block->children[2]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Internal error: catch block size unrecognized");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Boxed_Value &except) {
|
||||
for (size_t i = 1; i < this->children.size(); ++i) {
|
||||
chaiscript::eval::detail::Scope_Push_Pop catchscope(t_ss);
|
||||
const auto &catch_block = this->children[i];
|
||||
|
||||
if (catch_block->children.size() == 1) {
|
||||
//No variable capture, no guards
|
||||
retval = catch_block->children[0]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
else if (catch_block->children.size() == 2) {
|
||||
//Variable capture, no guards
|
||||
t_ss.add_object(catch_block->children[0]->text, except);
|
||||
retval = catch_block->children[1]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
else if (catch_block->children.size() == 3) {
|
||||
//Variable capture, guards
|
||||
t_ss.add_object(catch_block->children[0]->text, except);
|
||||
|
||||
bool guard;
|
||||
try {
|
||||
guard = boxed_cast<bool>(catch_block->children[1]->eval(t_ss));
|
||||
}
|
||||
catch (const exception::bad_boxed_cast &) {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
|
||||
throw exception::eval_error("Guard condition not boolean");
|
||||
}
|
||||
if (guard) {
|
||||
retval = catch_block->children[2]->eval(t_ss);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
throw exception::eval_error("Internal error: catch block size unrecognized");
|
||||
}
|
||||
}
|
||||
catch (Boxed_Value &e) {
|
||||
retval = handle_exception(t_ss, e);
|
||||
}
|
||||
catch (...) {
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
@@ -1303,6 +1347,7 @@ namespace chaiscript
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
if (this->children.back()->identifier == AST_Node_Type::Finally) {
|
||||
retval = this->children.back()->children[0]->eval(t_ss);
|
||||
}
|
||||
@@ -1343,11 +1388,12 @@ namespace chaiscript
|
||||
|
||||
//The first param of a method is always the implied this ptr.
|
||||
std::vector<std::string> t_param_names{"this"};
|
||||
dispatch::Param_Types param_types;
|
||||
|
||||
if ((this->children.size() > static_cast<size_t>(3 + class_offset)) && (this->children[(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
|
||||
for (const auto &child : this->children[(2 + class_offset)]->children) {
|
||||
t_param_names.push_back(child->text);
|
||||
}
|
||||
auto args = Arg_List_AST_Node::get_arg_names(this->children[(2 + class_offset)]);
|
||||
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
|
||||
param_types = Arg_List_AST_Node::get_arg_types(this->children[(2 + class_offset)], t_ss);
|
||||
|
||||
if (this->children.size() > static_cast<size_t>(4 + class_offset)) {
|
||||
guardnode = this->children[(3 + class_offset)];
|
||||
@@ -1377,29 +1423,35 @@ namespace chaiscript
|
||||
const std::string & function_name = this->children[(1 + class_offset)]->text;
|
||||
|
||||
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),
|
||||
static_cast<int>(numparams), this->children.back(), l_annotation, guard)),
|
||||
static_cast<int>(numparams), this->children.back(), param_types, l_annotation, guard)),
|
||||
function_name);
|
||||
|
||||
}
|
||||
else {
|
||||
try {
|
||||
// Do know type name
|
||||
// Do know type name (if this line fails, the catch block is called and the
|
||||
// other version is called, with no Type_Info object known)
|
||||
auto type = t_ss.get_type(class_name);
|
||||
param_types.push_front(class_name, type);
|
||||
|
||||
t_ss.add(
|
||||
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(),
|
||||
l_annotation, guard), t_ss.get_type(class_name)), function_name);
|
||||
param_types, l_annotation, guard), type), function_name);
|
||||
} catch (const std::range_error &) {
|
||||
param_types.push_front(class_name, Type_Info());
|
||||
// Do not know type name
|
||||
t_ss.add(
|
||||
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(),
|
||||
l_annotation, guard)), function_name);
|
||||
param_types, l_annotation, guard)), function_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -691,6 +691,25 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads an argument from input
|
||||
bool Arg() {
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
SkipWS();
|
||||
|
||||
if (!Id(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SkipWS();
|
||||
Id(true);
|
||||
|
||||
build_match(std::make_shared<eval::Arg_AST_Node>(), prev_stack_top);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Checks for a node annotation of the form "#<annotation>"
|
||||
bool Annotation() {
|
||||
SkipWS();
|
||||
@@ -1101,6 +1120,33 @@ namespace chaiscript
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads a comma-separated list of values from input, for function declarations
|
||||
bool Decl_Arg_List() {
|
||||
SkipWS(true);
|
||||
bool retval = false;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
|
||||
if (Arg()) {
|
||||
retval = true;
|
||||
while (Eol()) {}
|
||||
if (Char(',')) {
|
||||
do {
|
||||
while (Eol()) {}
|
||||
if (!Arg()) {
|
||||
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
|
||||
bool Arg_List() {
|
||||
SkipWS(true);
|
||||
@@ -1178,7 +1224,7 @@ namespace chaiscript
|
||||
retval = true;
|
||||
|
||||
if (Char('(')) {
|
||||
Arg_List();
|
||||
Decl_Arg_List();
|
||||
if (!Char(')')) {
|
||||
throw exception::eval_error("Incomplete anonymous function", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
@@ -1228,7 +1274,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
if (Char('(')) {
|
||||
Arg_List();
|
||||
Decl_Arg_List();
|
||||
if (!Char(')')) {
|
||||
throw exception::eval_error("Incomplete function definition", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
@@ -1283,7 +1329,7 @@ namespace chaiscript
|
||||
if (Keyword("catch", false)) {
|
||||
const auto catch_stack_top = m_match_stack.size();
|
||||
if (Char('(')) {
|
||||
if (!(Id(true) && Char(')'))) {
|
||||
if (!(Arg() && Char(')'))) {
|
||||
throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_line, m_col), *m_filename);
|
||||
}
|
||||
if (Char(':')) {
|
||||
|
@@ -455,37 +455,37 @@ def zip(x, y) {
|
||||
|
||||
|
||||
# Returns the position of the second value string in the first value string
|
||||
def string::find(substr) : is_type(substr, "string") {
|
||||
def string::find(string substr) {
|
||||
find(this, substr, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of last match of the second value string in the first value string
|
||||
def string::rfind(substr) : is_type(substr, "string") {
|
||||
def string::rfind(string substr) {
|
||||
rfind(this, substr, size_t(-1));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the first match of elements in the second value string in the first value string
|
||||
def string::find_first_of(list) : is_type(list, "string") {
|
||||
def string::find_first_of(string list) {
|
||||
find_first_of(this, list, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the last match of elements in the second value string in the first value string
|
||||
def string::find_last_of(list) : is_type(list, "string") {
|
||||
def string::find_last_of(string list) {
|
||||
find_last_of(this, list, size_t(-1));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the first non-matching element in the second value string in the first value string
|
||||
def string::find_first_not_of(list) : is_type(list, "string") {
|
||||
def string::find_first_not_of(string list) {
|
||||
find_first_not_of(this, list, size_t(0));
|
||||
}
|
||||
|
||||
|
||||
# Returns the position of the last non-matching element in the second value string in the first value string
|
||||
def string::find_last_not_of(list) : is_type(list, "string") {
|
||||
def string::find_last_not_of(string list) {
|
||||
find_last_not_of(this, list, size_t(-1));
|
||||
}
|
||||
|
||||
@@ -505,7 +505,7 @@ def string::trim() {
|
||||
}
|
||||
|
||||
|
||||
def find(container, value, compare_func) : call_exists(range, container) && is_type(compare_func, "Function") {
|
||||
def find(container, value, Function compare_func) : call_exists(range, container) {
|
||||
auto range := range(container);
|
||||
while (!range.empty()) {
|
||||
if (compare_func(range.front(), value)) {
|
||||
|
21
unittests/exception_typed.chai
Normal file
21
unittests/exception_typed.chai
Normal file
@@ -0,0 +1,21 @@
|
||||
auto x = 1
|
||||
try {
|
||||
throw(x)
|
||||
x = 2
|
||||
}
|
||||
catch(int e) {
|
||||
x = e + 3
|
||||
}
|
||||
assert_equal(4, x);
|
||||
|
||||
x = 1
|
||||
try {
|
||||
throw(x)
|
||||
x = 2
|
||||
}
|
||||
catch(string e) {
|
||||
}
|
||||
catch(e) {
|
||||
x = e + 4
|
||||
}
|
||||
assert_equal(5, x);
|
34
unittests/exception_typed_2.chai
Normal file
34
unittests/exception_typed_2.chai
Normal file
@@ -0,0 +1,34 @@
|
||||
auto results = [];
|
||||
|
||||
for (auto i = 2; i < 6; ++i) {
|
||||
try {
|
||||
throw(i)
|
||||
}
|
||||
catch(int e) : e < 2 {
|
||||
results.push_back("c1: " + e.to_string());
|
||||
}
|
||||
catch(int e) : e < 4 {
|
||||
results.push_back("c2: " + e.to_string());
|
||||
}
|
||||
catch(e) {
|
||||
results.push_back("c3: " + e.to_string());
|
||||
}
|
||||
catch {
|
||||
// Should never get called
|
||||
assert_equal(false, true)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
throw(3)
|
||||
}
|
||||
catch(int e) : e < 3
|
||||
{
|
||||
// Should never get called
|
||||
assert_equal(false, true);
|
||||
}
|
||||
catch {
|
||||
results.push_back("defaultcatch");
|
||||
}
|
||||
|
||||
assert_equal(["c2: 2", "c2: 3", "c3: 4", "c3: 5", "defaultcatch"], results);
|
Reference in New Issue
Block a user