Add support for chai objects by adding methods and attrs

This commit is contained in:
Jonathan Turner
2009-09-19 15:32:12 +00:00
parent 18fc4d419f
commit 7c244d25b5
9 changed files with 150 additions and 5 deletions

View File

@@ -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,
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,
Inline_Range, Annotation, Try, Catch }; };
Inline_Range, Annotation, Try, Catch, Method, Attr_Decl }; };
/**
* 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",
"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",
"Inline_Range", "Annotation", "Try", "Catch"};
"Inline_Range", "Annotation", "Try", "Catch", "Method", "Attr_Decl"};
return token_types[tokentype];
}

View File

@@ -167,6 +167,7 @@ namespace chaiscript
for (i = node->children.size()-3; ((int)i) >= 0; i -= 2) {
if (node->children[i+1]->text == "=") {
Boxed_Value lhs = eval_token(ss, node->children[i]);
try {
if (lhs.is_unknown())
{
@@ -225,6 +226,22 @@ namespace chaiscript
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.
*/
@@ -587,7 +604,6 @@ namespace chaiscript
Boxed_Value retval;
retval = Boxed_Value();
ss.new_scope();
try {
retval = eval_token(ss, node->children[0]);
@@ -863,6 +879,75 @@ namespace chaiscript
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)
*/
@@ -1047,6 +1132,14 @@ namespace chaiscript
return eval_def(ss, node);
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) :
return eval_lambda(ss, node);
break;

View File

@@ -867,7 +867,7 @@ namespace chaiscript
bool Def() {
bool retval = false;
bool is_annotated = false;
bool is_method = false;
TokenPtr annotation;
if (Annotation()) {
@@ -886,6 +886,15 @@ namespace chaiscript
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('(')) {
Arg_List();
if (!Char(')')) {
@@ -906,7 +915,12 @@ namespace chaiscript
throw Eval_Error("Incomplete function definition", File_Position(line, col), filename);
}
if (is_method) {
build_match(Token_Type::Method, prev_stack_top);
}
else {
build_match(Token_Type::Def, prev_stack_top);
}
if (is_annotated) {
match_stack.back()->annotation = annotation;
@@ -1230,6 +1244,22 @@ namespace chaiscript
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;
}

View 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))

View File

@@ -0,0 +1 @@
7

View 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)

View File

@@ -0,0 +1,2 @@
constructed any old: 12
constructed less than 10: 3

View 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)

View File

@@ -0,0 +1,2 @@
e less than 10
e is some value