parent
fac8f3ec90
commit
c97a69537d
@ -455,6 +455,13 @@ the contained function.
|
||||
|
||||
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
|
||||
|
||||
|
@ -31,7 +31,8 @@ namespace chaiscript
|
||||
{
|
||||
static const std::set<std::string> m_reserved_words
|
||||
= {"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;
|
||||
}
|
||||
|
||||
|
@ -1368,30 +1368,27 @@ namespace chaiscript
|
||||
|
||||
AST_Node_Impl_Ptr<T> guardnode;
|
||||
|
||||
const auto d = t_ss->get_parent_locals();
|
||||
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;
|
||||
const std::string & class_name = this->children[0]->text;
|
||||
|
||||
//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[static_cast<size_t>(2 + class_offset)]->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)]);
|
||||
if ((this->children.size() > 3)
|
||||
&& (this->children[2]->identifier == AST_Node_Type::Arg_List)) {
|
||||
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());
|
||||
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)) {
|
||||
guardnode = this->children[static_cast<size_t>(3 + class_offset)];
|
||||
if (this->children.size() > 4) {
|
||||
guardnode = this->children[3];
|
||||
}
|
||||
}
|
||||
else {
|
||||
//no parameters
|
||||
|
||||
if (this->children.size() > static_cast<size_t>(3 + class_offset)) {
|
||||
guardnode = this->children[static_cast<size_t>(2 + class_offset)];
|
||||
if (this->children.size() > 3) {
|
||||
guardnode = this->children[2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -1408,7 +1405,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (function_name == class_name) {
|
||||
@ -1454,13 +1451,10 @@ namespace chaiscript
|
||||
|
||||
Boxed_Value eval_internal(const chaiscript::detail::Dispatch_State &t_ss) const override
|
||||
{
|
||||
const auto &d = t_ss->get_parent_locals();
|
||||
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;
|
||||
std::string class_name = this->children[0]->text;
|
||||
|
||||
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(
|
||||
std::make_shared<dispatch::detail::Dynamic_Object_Function>(
|
||||
@ -1470,7 +1464,7 @@ namespace chaiscript
|
||||
}),
|
||||
true
|
||||
|
||||
), this->children[static_cast<size_t>(1 + class_offset)]->text);
|
||||
), this->children[1]->text);
|
||||
} catch (const exception::name_conflict_error &e) {
|
||||
throw exception::eval_error("Attribute redefined '" + e.name() + "'");
|
||||
}
|
||||
|
@ -839,6 +839,41 @@ namespace chaiscript
|
||||
} else if (text == "NaN") {
|
||||
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())));
|
||||
} 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 == "_") {
|
||||
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>())));
|
||||
@ -1517,7 +1552,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1525,6 +1560,10 @@ namespace chaiscript
|
||||
if (Keyword("def")) {
|
||||
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)) {
|
||||
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);
|
||||
}
|
||||
|
||||
const auto class_name = m_match_stack.back()->text;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1908,7 +1948,7 @@ namespace chaiscript
|
||||
|
||||
|
||||
/// 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;
|
||||
|
||||
const auto prev_stack_top = m_match_stack.size();
|
||||
@ -1916,7 +1956,7 @@ namespace chaiscript
|
||||
if (Char('{')) {
|
||||
retval = true;
|
||||
|
||||
Class_Statements();
|
||||
Class_Statements(t_class_name);
|
||||
if (!Char('}')) {
|
||||
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
|
||||
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;
|
||||
|
||||
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"))) {
|
||||
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)) {
|
||||
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
|
||||
bool Prefix() {
|
||||
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)
|
||||
{
|
||||
@ -2351,7 +2393,7 @@ namespace chaiscript
|
||||
}
|
||||
|
||||
/// Parses statements allowed inside of a class block
|
||||
bool Class_Statements() {
|
||||
bool Class_Statements(const std::string &t_class_name) {
|
||||
bool retval = false;
|
||||
|
||||
bool has_more = true;
|
||||
@ -2359,7 +2401,7 @@ namespace chaiscript
|
||||
|
||||
while (has_more) {
|
||||
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) {
|
||||
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)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user