@@ -455,6 +455,13 @@ the contained function.
|
|||||||
|
|
||||||
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
|
If both a 2 parameter and a 3 parameter signature match, the 3 parameter function always wins.
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
* `__LINE__` Current file line number
|
||||||
|
* `__FILE__` Full path of current file
|
||||||
|
* `__CLASS__` Name of current class
|
||||||
|
* `__FUNC__` Mame of current function
|
||||||
|
|
||||||
|
|
||||||
# Built In Functions
|
# Built In Functions
|
||||||
|
|
||||||
|
@@ -31,7 +31,8 @@ namespace chaiscript
|
|||||||
{
|
{
|
||||||
static const std::set<std::string> m_reserved_words
|
static const std::set<std::string> m_reserved_words
|
||||||
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
= {"def", "fun", "while", "for", "if", "else", "&&", "||", ",", "auto",
|
||||||
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_"};
|
"return", "break", "true", "false", "class", "attr", "var", "global", "GLOBAL", "_",
|
||||||
|
"__LINE__", "__FILE__", "__FUNC__", "__CLASS__"};
|
||||||
return m_reserved_words.count(name) > 0;
|
return m_reserved_words.count(name) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1368,30 +1368,27 @@ namespace chaiscript
|
|||||||
|
|
||||||
AST_Node_Impl_Ptr<T> guardnode;
|
AST_Node_Impl_Ptr<T> guardnode;
|
||||||
|
|
||||||
const auto d = t_ss->get_parent_locals();
|
const std::string & class_name = this->children[0]->text;
|
||||||
const auto itr = d.find("_current_class_name");
|
|
||||||
const auto class_offset = (itr != d.end())?-1:0;
|
|
||||||
const std::string & class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
|
||||||
|
|
||||||
//The first param of a method is always the implied this ptr.
|
//The first param of a method is always the implied this ptr.
|
||||||
std::vector<std::string> t_param_names{"this"};
|
std::vector<std::string> t_param_names{"this"};
|
||||||
dispatch::Param_Types param_types;
|
dispatch::Param_Types param_types;
|
||||||
|
|
||||||
if ((this->children.size() > static_cast<size_t>(3 + class_offset))
|
if ((this->children.size() > 3)
|
||||||
&& (this->children[static_cast<size_t>(2 + class_offset)]->identifier == AST_Node_Type::Arg_List)) {
|
&& (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
|
||||||
auto args = Arg_List_AST_Node<T>::get_arg_names(this->children[static_cast<size_t>(2 + class_offset)]);
|
auto args = Arg_List_AST_Node<T>::get_arg_names(this->children[2]);
|
||||||
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
|
t_param_names.insert(t_param_names.end(), args.begin(), args.end());
|
||||||
param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[static_cast<size_t>(2 + class_offset)], t_ss);
|
param_types = Arg_List_AST_Node<T>::get_arg_types(this->children[2], t_ss);
|
||||||
|
|
||||||
if (this->children.size() > static_cast<size_t>(4 + class_offset)) {
|
if (this->children.size() > 4) {
|
||||||
guardnode = this->children[static_cast<size_t>(3 + class_offset)];
|
guardnode = this->children[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//no parameters
|
//no parameters
|
||||||
|
|
||||||
if (this->children.size() > static_cast<size_t>(3 + class_offset)) {
|
if (this->children.size() > 3) {
|
||||||
guardnode = this->children[static_cast<size_t>(2 + class_offset)];
|
guardnode = this->children[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1408,7 +1405,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const std::string & function_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
|
const std::string & function_name = this->children[1]->text;
|
||||||
auto node = this->children.back();
|
auto node = this->children.back();
|
||||||
|
|
||||||
if (function_name == class_name) {
|
if (function_name == class_name) {
|
||||||
@@ -1454,13 +1451,10 @@ namespace chaiscript
|
|||||||
|
|
||||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
|
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
|
||||||
{
|
{
|
||||||
const auto &d = t_ss->get_parent_locals();
|
std::string class_name = this->children[0]->text;
|
||||||
const auto itr = d.find("_current_class_name");
|
|
||||||
const auto class_offset = (itr != d.end())?-1:0;
|
|
||||||
std::string class_name = (itr != d.end())?std::string(boxed_cast<std::string>(itr->second)):this->children[0]->text;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string attr_name = this->children[static_cast<size_t>(1 + class_offset)]->text;
|
std::string attr_name = this->children[1]->text;
|
||||||
|
|
||||||
t_ss->add(
|
t_ss->add(
|
||||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
|
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
|
||||||
@@ -1470,7 +1464,7 @@ namespace chaiscript
|
|||||||
}),
|
}),
|
||||||
true
|
true
|
||||||
|
|
||||||
), this->children[static_cast<size_t>(1 + class_offset)]->text);
|
), this->children[1]->text);
|
||||||
} catch (const exception::name_conflict_error &e) {
|
} catch (const exception::name_conflict_error &e) {
|
||||||
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
|
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
|
||||||
}
|
}
|
||||||
|
@@ -839,6 +839,41 @@ namespace chaiscript
|
|||||||
} else if (text == "NaN") {
|
} else if (text == "NaN") {
|
||||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
const_var(std::numeric_limits<double>::quiet_NaN())));
|
const_var(std::numeric_limits<double>::quiet_NaN())));
|
||||||
|
} else if (text == "__LINE__") {
|
||||||
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
|
const_var(start.line)));
|
||||||
|
} else if (text == "__FILE__") {
|
||||||
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
|
const_var(m_filename)));
|
||||||
|
} else if (text == "__FUNC__") {
|
||||||
|
const std::string fun_name = [&]()->std::string{
|
||||||
|
for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx)
|
||||||
|
{
|
||||||
|
if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||||
|
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
|
||||||
|
return m_match_stack[idx-1]->text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "NOT_IN_FUNCTION";
|
||||||
|
}();
|
||||||
|
|
||||||
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
|
const_var(std::move(fun_name))));
|
||||||
|
} else if (text == "__CLASS__") {
|
||||||
|
const std::string fun_name = [&]()->std::string{
|
||||||
|
for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx)
|
||||||
|
{
|
||||||
|
if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
|
||||||
|
&& m_match_stack[idx-1]->identifier == AST_Node_Type::Id
|
||||||
|
&& m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
|
||||||
|
return m_match_stack[idx-2]->text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "NOT_IN_CLASS";
|
||||||
|
}();
|
||||||
|
|
||||||
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
|
const_var(std::move(fun_name))));
|
||||||
} else if (text == "_") {
|
} else if (text == "_") {
|
||||||
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(text, start.line, start.col,
|
||||||
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
|
Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
|
||||||
@@ -1517,7 +1552,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a function definition from input
|
/// Reads a function definition from input
|
||||||
bool Def(const bool t_class_context = false) {
|
bool Def(const bool t_class_context = false, const std::string &t_class_name = "") {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
@@ -1525,6 +1560,10 @@ namespace chaiscript
|
|||||||
if (Keyword("def")) {
|
if (Keyword("def")) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
|
if (t_class_context) {
|
||||||
|
m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(t_class_name, m_position.line, m_position.col));
|
||||||
|
}
|
||||||
|
|
||||||
if (!Id(true)) {
|
if (!Id(true)) {
|
||||||
throw exception::eval_error("Missing function name in definition", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Missing function name in definition", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
@@ -1708,10 +1747,11 @@ namespace chaiscript
|
|||||||
throw exception::eval_error("Missing class name in definition", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Missing class name in definition", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto class_name = m_match_stack.back()->text;
|
||||||
|
|
||||||
while (Eol()) {}
|
while (Eol()) {}
|
||||||
|
|
||||||
if (!Class_Block()) {
|
if (!Class_Block(class_name)) {
|
||||||
throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1908,7 +1948,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
|
|
||||||
/// Reads a curly-brace C-style class block from input
|
/// Reads a curly-brace C-style class block from input
|
||||||
bool Class_Block() {
|
bool Class_Block(const std::string &t_class_name) {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
@@ -1916,7 +1956,7 @@ namespace chaiscript
|
|||||||
if (Char('{')) {
|
if (Char('{')) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
Class_Statements();
|
Class_Statements(t_class_name);
|
||||||
if (!Char('}')) {
|
if (!Char('}')) {
|
||||||
throw exception::eval_error("Incomplete class block", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Incomplete class block", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
@@ -2059,7 +2099,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a variable declaration from input
|
/// Reads a variable declaration from input
|
||||||
bool Var_Decl(const bool t_class_context = false) {
|
bool Var_Decl(const bool t_class_context = false, const std::string &t_class_name = "") {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
@@ -2067,6 +2107,8 @@ namespace chaiscript
|
|||||||
if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) {
|
if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) {
|
||||||
retval = true;
|
retval = true;
|
||||||
|
|
||||||
|
m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(t_class_name, m_position.line, m_position.col));
|
||||||
|
|
||||||
if (!Id(true)) {
|
if (!Id(true)) {
|
||||||
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
|
||||||
}
|
}
|
||||||
@@ -2176,7 +2218,7 @@ namespace chaiscript
|
|||||||
/// Reads a unary prefixed expression from input
|
/// Reads a unary prefixed expression from input
|
||||||
bool Prefix() {
|
bool Prefix() {
|
||||||
const auto prev_stack_top = m_match_stack.size();
|
const auto prev_stack_top = m_match_stack.size();
|
||||||
constexpr const std::array<const char *, 6> prefix_opers{"++", "--", "-", "+", "!", "~"};
|
constexpr const std::array<const char *, 6> prefix_opers{{"++", "--", "-", "+", "!", "~"}};
|
||||||
|
|
||||||
for (const auto &oper : prefix_opers)
|
for (const auto &oper : prefix_opers)
|
||||||
{
|
{
|
||||||
@@ -2351,7 +2393,7 @@ namespace chaiscript
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parses statements allowed inside of a class block
|
/// Parses statements allowed inside of a class block
|
||||||
bool Class_Statements() {
|
bool Class_Statements(const std::string &t_class_name) {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
bool has_more = true;
|
bool has_more = true;
|
||||||
@@ -2359,7 +2401,7 @@ namespace chaiscript
|
|||||||
|
|
||||||
while (has_more) {
|
while (has_more) {
|
||||||
const auto start = m_position;
|
const auto start = m_position;
|
||||||
if (Def(true) || Var_Decl(true)) {
|
if (Def(true, t_class_name) || Var_Decl(true, t_class_name)) {
|
||||||
if (!saw_eol) {
|
if (!saw_eol) {
|
||||||
throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename);
|
throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename);
|
||||||
}
|
}
|
||||||
|
42
unittests/execution_context.chai
Normal file
42
unittests/execution_context.chai
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
|
||||||
|
assert_equal(__LINE__, 3)
|
||||||
|
|
||||||
|
def f() {
|
||||||
|
[__LINE__, __CLASS__, __FUNC__]
|
||||||
|
}
|
||||||
|
|
||||||
|
var res = f()
|
||||||
|
|
||||||
|
assert_equal(res[0], 6)
|
||||||
|
assert_equal(res[1], "NOT_IN_CLASS")
|
||||||
|
assert_equal(res[2], "f")
|
||||||
|
|
||||||
|
assert_equal(__CLASS__, "NOT_IN_CLASS")
|
||||||
|
assert_equal(__FUNC__, "NOT_IN_FUNCTION")
|
||||||
|
|
||||||
|
class C
|
||||||
|
{
|
||||||
|
def C() {}
|
||||||
|
def member() { [__LINE__, __CLASS__, __FUNC__]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
var c = C();
|
||||||
|
|
||||||
|
var res2 = c.member();
|
||||||
|
|
||||||
|
assert_equal(res2[0], 21)
|
||||||
|
assert_equal(res2[1], "C")
|
||||||
|
assert_equal(res2[2], "member")
|
||||||
|
|
||||||
|
def C::member2() { [__LINE__, __CLASS__, __FUNC__]; }
|
||||||
|
|
||||||
|
var res3 = c.member2();
|
||||||
|
|
||||||
|
assert_equal(res3[0], 32)
|
||||||
|
assert_equal(res3[1], "C")
|
||||||
|
assert_equal(res3[2], "member2")
|
||||||
|
|
||||||
|
assert_true(__FILE__.find("execution_context.chai") != -1)
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user