Add support for chai objects by adding methods and attrs
This commit is contained in:
@@ -41,7 +41,7 @@ namespace chaiscript
|
|||||||
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
class Token_Type { public: enum Type { Error, Int, Float, Id, Char, Str, Eol, Fun_Call, Inplace_Fun_Call, Arg_List, Variable, Equation, Var_Decl,
|
||||||
Expression, Comparison, Additive, Multiplicative, Negate, Not, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
Expression, Comparison, Additive, Multiplicative, Negate, Not, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
||||||
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
|
Lambda, Block, Def, While, If, For, Inline_Array, Inline_Map, Return, File, Prefix, Break, Map_Pair, Value_Range,
|
||||||
Inline_Range, Annotation, Try, Catch }; };
|
Inline_Range, Annotation, Try, Catch, Method, Attr_Decl }; };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper lookup to get the name of each node type
|
* Helper lookup to get the name of each node type
|
||||||
@@ -50,7 +50,7 @@ namespace chaiscript
|
|||||||
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
const char *token_types[] = { "Internal Parser Error", "Int", "Float", "Id", "Char", "Str", "Eol", "Fun_Call", "Inplace_Fun_Call", "Arg_List", "Variable", "Equation", "Var_Decl",
|
||||||
"Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
"Expression", "Comparison", "Additive", "Multiplicative", "Negate", "Not", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
||||||
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
|
"Lambda", "Block", "Def", "While", "If", "For", "Inline_Array", "Inline_Map", "Return", "File", "Prefix", "Break", "Map_Pair", "Value_Range",
|
||||||
"Inline_Range", "Annotation", "Try", "Catch"};
|
"Inline_Range", "Annotation", "Try", "Catch", "Method", "Attr_Decl"};
|
||||||
|
|
||||||
return token_types[tokentype];
|
return token_types[tokentype];
|
||||||
}
|
}
|
||||||
|
@@ -167,6 +167,7 @@ namespace chaiscript
|
|||||||
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
|
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
|
||||||
if (node->children[i+1]->text == "=") {
|
if (node->children[i+1]->text == "=") {
|
||||||
Boxed_Value lhs = eval_token(ss, node->children[i]);
|
Boxed_Value lhs = eval_token(ss, node->children[i]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (lhs.is_unknown())
|
if (lhs.is_unknown())
|
||||||
{
|
{
|
||||||
@@ -225,6 +226,22 @@ namespace chaiscript
|
|||||||
return ss.get_object(node->children[0]->text);
|
return ss.get_object(node->children[0]->text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates an attribute declaration
|
||||||
|
*/
|
||||||
|
template <typename Eval_System>
|
||||||
|
Boxed_Value eval_attr_decl(Eval_System &ss, const TokenPtr &node) {
|
||||||
|
try {
|
||||||
|
ss.add(fun(boost::function<Boxed_Value (Dynamic_Object &)>(boost::bind(&dynamic_object_attribute, node->children[0]->text,
|
||||||
|
node->children[1]->text, _1))), node->children[1]->text);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (reserved_word_error &) {
|
||||||
|
throw Eval_Error("Reserved word used as attribute '" + node->children[1]->text + "'", node);
|
||||||
|
}
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates binary boolean operators. Respects short-circuiting rules.
|
* Evaluates binary boolean operators. Respects short-circuiting rules.
|
||||||
*/
|
*/
|
||||||
@@ -586,7 +603,6 @@ namespace chaiscript
|
|||||||
Boxed_Value eval_try(Eval_System &ss, const TokenPtr &node) {
|
Boxed_Value eval_try(Eval_System &ss, const TokenPtr &node) {
|
||||||
Boxed_Value retval;
|
Boxed_Value retval;
|
||||||
retval = Boxed_Value();
|
retval = Boxed_Value();
|
||||||
|
|
||||||
|
|
||||||
ss.new_scope();
|
ss.new_scope();
|
||||||
try {
|
try {
|
||||||
@@ -863,6 +879,75 @@ namespace chaiscript
|
|||||||
return Boxed_Value();
|
return Boxed_Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a function definition
|
||||||
|
*/
|
||||||
|
template <typename Eval_System>
|
||||||
|
Boxed_Value eval_def_method(Eval_System &ss, const TokenPtr &node) {
|
||||||
|
//TODO: Merge with eval_def cleanly someday?
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
std::vector<std::string> param_names;
|
||||||
|
std::string annotation = node->annotation?node->annotation->text:"";
|
||||||
|
boost::shared_ptr<Dynamic_Proxy_Function> guard;
|
||||||
|
size_t numparams;
|
||||||
|
std::string class_name = node->children[0]->text;
|
||||||
|
std::string function_name = node->children[1]->text;
|
||||||
|
TokenPtr guardnode;
|
||||||
|
|
||||||
|
//The first param of a method is always the implied this ptr.
|
||||||
|
param_names.push_back("this");
|
||||||
|
|
||||||
|
if ((node->children.size() > 3) && (node->children[2]->identifier == Token_Type::Arg_List)) {
|
||||||
|
for (i = 0; i < node->children[2]->children.size(); ++i) {
|
||||||
|
param_names.push_back(node->children[2]->children[i]->text);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->children.size() > 4) {
|
||||||
|
guardnode = node->children[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//no parameters
|
||||||
|
|
||||||
|
if (node->children.size() > 3) {
|
||||||
|
guardnode = node->children[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numparams = param_names.size();
|
||||||
|
|
||||||
|
if (guardnode) {
|
||||||
|
guard = boost::shared_ptr<Dynamic_Proxy_Function>
|
||||||
|
(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), guardnode,
|
||||||
|
param_names, _1), numparams));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (function_name == class_name) {
|
||||||
|
ss.add(Proxy_Function
|
||||||
|
(new Dynamic_Object_Constructor(class_name, Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), node->children.back(),
|
||||||
|
param_names, _1), numparams,
|
||||||
|
annotation, guard)))), function_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ss.add(Proxy_Function
|
||||||
|
(new Dynamic_Object_Function(class_name, Proxy_Function(new Dynamic_Proxy_Function(boost::bind(&eval_function<Eval_System>,
|
||||||
|
boost::ref(ss), node->children.back(),
|
||||||
|
param_names, _1), numparams,
|
||||||
|
annotation, guard)))), function_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (reserved_word_error &) {
|
||||||
|
throw Eval_Error("Reserved word used as method name '" + function_name + "'", node);
|
||||||
|
}
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates a lambda (anonymous function)
|
* Evaluates a lambda (anonymous function)
|
||||||
*/
|
*/
|
||||||
@@ -1047,6 +1132,14 @@ namespace chaiscript
|
|||||||
return eval_def(ss, node);
|
return eval_def(ss, node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case (Token_Type::Method) :
|
||||||
|
return eval_def_method(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case (Token_Type::Attr_Decl) :
|
||||||
|
return eval_attr_decl(ss, node);
|
||||||
|
break;
|
||||||
|
|
||||||
case (Token_Type::Lambda) :
|
case (Token_Type::Lambda) :
|
||||||
return eval_lambda(ss, node);
|
return eval_lambda(ss, node);
|
||||||
break;
|
break;
|
||||||
|
@@ -867,7 +867,7 @@ namespace chaiscript
|
|||||||
bool Def() {
|
bool Def() {
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
bool is_annotated = false;
|
bool is_annotated = false;
|
||||||
|
bool is_method = false;
|
||||||
TokenPtr annotation;
|
TokenPtr annotation;
|
||||||
|
|
||||||
if (Annotation()) {
|
if (Annotation()) {
|
||||||
@@ -886,6 +886,15 @@ namespace chaiscript
|
|||||||
throw Eval_Error("Missing function name in definition", File_Position(line, col), filename);
|
throw Eval_Error("Missing function name in definition", File_Position(line, col), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Symbol("::", false)) {
|
||||||
|
//We're now a method
|
||||||
|
is_method = true;
|
||||||
|
|
||||||
|
if (!Id(true)) {
|
||||||
|
throw Eval_Error("Missing method name in definition", File_Position(line, col), filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Char('(')) {
|
if (Char('(')) {
|
||||||
Arg_List();
|
Arg_List();
|
||||||
if (!Char(')')) {
|
if (!Char(')')) {
|
||||||
@@ -906,7 +915,12 @@ namespace chaiscript
|
|||||||
throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
|
throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
build_match(Token_Type::Def, prev_stack_top);
|
if (is_method) {
|
||||||
|
build_match(Token_Type::Method, prev_stack_top);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
build_match(Token_Type::Def, prev_stack_top);
|
||||||
|
}
|
||||||
|
|
||||||
if (is_annotated) {
|
if (is_annotated) {
|
||||||
match_stack.back()->annotation = annotation;
|
match_stack.back()->annotation = annotation;
|
||||||
@@ -1230,6 +1244,22 @@ namespace chaiscript
|
|||||||
|
|
||||||
build_match(Token_Type::Var_Decl, prev_stack_top);
|
build_match(Token_Type::Var_Decl, prev_stack_top);
|
||||||
}
|
}
|
||||||
|
else if (Keyword("attr")) {
|
||||||
|
retval = true;
|
||||||
|
|
||||||
|
if (!Id(true)) {
|
||||||
|
throw Eval_Error("Incomplete attribute declaration", File_Position(line, col), filename);
|
||||||
|
}
|
||||||
|
if (!Symbol("::", false)) {
|
||||||
|
throw Eval_Error("Incomplete attribute declaration", File_Position(line, col), filename);
|
||||||
|
}
|
||||||
|
if (!Id(true)) {
|
||||||
|
throw Eval_Error("Missing attribute name in definition", File_Position(line, col), filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
build_match(Token_Type::Attr_Decl, prev_stack_top);
|
||||||
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
5
unittests/object_attr.chai
Normal file
5
unittests/object_attr.chai
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
attr bob::z
|
||||||
|
def bob::bob() { this.z = 10 }
|
||||||
|
var x = bob()
|
||||||
|
def bob::fred(x) { this.z - x }
|
||||||
|
print(x.fred(3))
|
1
unittests/object_attr.txt
Normal file
1
unittests/object_attr.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7
|
5
unittests/object_constructor_guards.chai
Normal file
5
unittests/object_constructor_guards.chai
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
def bob::bob(x) : x < 10 { print("constructed less than 10: " + x.to_string()) }
|
||||||
|
def bob::bob(x) { print("constructed any old: " + x.to_string()) }
|
||||||
|
|
||||||
|
var b = bob(12)
|
||||||
|
var c = bob(3)
|
2
unittests/object_constructor_guards.txt
Normal file
2
unittests/object_constructor_guards.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
constructed any old: 12
|
||||||
|
constructed less than 10: 3
|
7
unittests/object_method_guards.chai
Normal file
7
unittests/object_method_guards.chai
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
def bob::bob() { }
|
||||||
|
def bob::fred(e) : e < 10 { print("e less than 10") }
|
||||||
|
def bob::fred(e) { print("e is some value") }
|
||||||
|
|
||||||
|
var b = bob()
|
||||||
|
b.fred(3)
|
||||||
|
b.fred(12)
|
2
unittests/object_method_guards.txt
Normal file
2
unittests/object_method_guards.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
e less than 10
|
||||||
|
e is some value
|
Reference in New Issue
Block a user