Add support for switch/case/default statements.
This commit is contained in:
parent
af1e02b0bb
commit
4e14a57016
@ -23,7 +23,7 @@ namespace chaiscript
|
|||||||
Comparison, Addition, Subtraction, Multiplication, Division, Modulus, Array_Call, Dot_Access, Quoted_String, Single_Quoted_String,
|
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, 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, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
Inline_Range, Annotation, Try, Catch, Finally, Method, Attr_Decl, Shift, Equality, Bitwise_And, Bitwise_Xor, Bitwise_Or,
|
||||||
Logical_And, Logical_Or
|
Logical_And, Logical_Or, Switch, Case, Default
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ namespace chaiscript
|
|||||||
"Comparison", "Addition", "Subtraction", "Multiplication", "Division", "Modulus", "Array_Call", "Dot_Access", "Quoted_String", "Single_Quoted_String",
|
"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", "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", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
"Inline_Range", "Annotation", "Try", "Catch", "Finally", "Method", "Attr_Decl", "Shift", "Equality", "Bitwise_And", "Bitwise_Xor", "Bitwise_Or",
|
||||||
"Logical_And", "Logical_Or"};
|
"Logical_And", "Logical_Or", "Switch", "Case", "Default"};
|
||||||
|
|
||||||
return ast_node_types[ast_node_type];
|
return ast_node_types[ast_node_type];
|
||||||
}
|
}
|
||||||
|
@ -780,6 +780,79 @@ namespace chaiscript
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Switch_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Switch_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Switch, const boost::shared_ptr<std::string> &t_fname=boost::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, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||||
|
virtual ~Switch_AST_Node() {}
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||||
|
Boxed_Value match_value;
|
||||||
|
bool breaking = false;
|
||||||
|
int currentCase = 1;
|
||||||
|
bool hasMatched = false;
|
||||||
|
|
||||||
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
|
match_value = this->children[0]->eval(t_ss);
|
||||||
|
|
||||||
|
while (!breaking) {
|
||||||
|
try {
|
||||||
|
if (this->children[currentCase]->identifier == AST_Node_Type::Case) {
|
||||||
|
//This is a little odd, but because want to see both the switch and the case simultaneously, I do a downcast here.
|
||||||
|
try {
|
||||||
|
if (hasMatched || boxed_cast<bool>(t_ss.call_function("==", match_value, this->children[currentCase]->children[0]->eval(t_ss)))) {
|
||||||
|
this->children[currentCase]->eval(t_ss);
|
||||||
|
hasMatched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const exception::bad_boxed_cast &) {
|
||||||
|
throw exception::eval_error("Internal error: case guard evaluation not boolean");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (this->children[currentCase]->identifier == AST_Node_Type::Default) {
|
||||||
|
this->children[currentCase]->eval(t_ss);
|
||||||
|
breaking = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (detail::Break_Loop &) {
|
||||||
|
breaking = true;
|
||||||
|
}
|
||||||
|
++currentCase;
|
||||||
|
if (currentCase == this->children.size())
|
||||||
|
breaking = true;
|
||||||
|
}
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Case_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Case_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Case, const boost::shared_ptr<std::string> &t_fname=boost::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, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||||
|
virtual ~Case_AST_Node() {}
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||||
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
|
this->children[1]->eval(t_ss);
|
||||||
|
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Default_AST_Node : public AST_Node {
|
||||||
|
public:
|
||||||
|
Default_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Default, const boost::shared_ptr<std::string> &t_fname=boost::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, t_id, t_fname, t_start_line, t_start_col, t_end_line, t_end_col) { }
|
||||||
|
virtual ~Default_AST_Node() {}
|
||||||
|
virtual Boxed_Value eval_internal(chaiscript::detail::Dispatch_Engine &t_ss) {
|
||||||
|
chaiscript::eval::detail::Scope_Push_Pop spp(t_ss);
|
||||||
|
|
||||||
|
this->children[0]->eval(t_ss);
|
||||||
|
|
||||||
|
return Boxed_Value();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Inline_Array_AST_Node : public AST_Node {
|
struct Inline_Array_AST_Node : public AST_Node {
|
||||||
public:
|
public:
|
||||||
Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
Inline_Array_AST_Node(const std::string &t_ast_node_text = "", int t_id = AST_Node_Type::Inline_Array, const boost::shared_ptr<std::string> &t_fname=boost::shared_ptr<std::string>(), int t_start_line = 0, int t_start_col = 0, int t_end_line = 0, int t_end_col = 0) :
|
||||||
|
@ -1415,6 +1415,92 @@ namespace chaiscript
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a case block from input
|
||||||
|
*/
|
||||||
|
bool Case() {
|
||||||
|
bool retval = false;
|
||||||
|
|
||||||
|
size_t prev_stack_top = m_match_stack.size();
|
||||||
|
|
||||||
|
if (Keyword("case")) {
|
||||||
|
retval = true;
|
||||||
|
|
||||||
|
if (!Char('(')) {
|
||||||
|
throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Operator() && Char(')'))) {
|
||||||
|
throw exception::eval_error("Incomplete 'case' expression", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Eol()) {}
|
||||||
|
|
||||||
|
if (!Block()) {
|
||||||
|
throw exception::eval_error("Incomplete 'case' block", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_match(AST_NodePtr(new eval::Case_AST_Node()), prev_stack_top);
|
||||||
|
}
|
||||||
|
else if (Keyword("default")) {
|
||||||
|
while (Eol()) {}
|
||||||
|
|
||||||
|
if (!Block()) {
|
||||||
|
throw exception::eval_error("Incomplete 'default' block", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_match(AST_NodePtr(new eval::Default_AST_Node()), prev_stack_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a switch statement from input
|
||||||
|
*/
|
||||||
|
bool Switch() {
|
||||||
|
bool retval = false;
|
||||||
|
|
||||||
|
size_t prev_stack_top = m_match_stack.size();
|
||||||
|
|
||||||
|
if (Keyword("switch")) {
|
||||||
|
retval = true;
|
||||||
|
|
||||||
|
if (!Char('(')) {
|
||||||
|
throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(Operator() && Char(')'))) {
|
||||||
|
throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Eol()) {}
|
||||||
|
|
||||||
|
if (Char('{')) {
|
||||||
|
retval = true;
|
||||||
|
|
||||||
|
while (Eol()) {}
|
||||||
|
|
||||||
|
while (Case()) {
|
||||||
|
while (Eol());
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Eol());
|
||||||
|
|
||||||
|
if (!Char('}')) {
|
||||||
|
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw exception::eval_error("Incomplete block", File_Position(m_line, m_col), *m_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_match(AST_NodePtr(new eval::Switch_AST_Node()), prev_stack_top);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads a curly-brace C-style block from input
|
* Reads a curly-brace C-style block from input
|
||||||
*/
|
*/
|
||||||
@ -1928,6 +2014,14 @@ namespace chaiscript
|
|||||||
retval = true;
|
retval = true;
|
||||||
saw_eol = true;
|
saw_eol = true;
|
||||||
}
|
}
|
||||||
|
else if (Switch()) {
|
||||||
|
if (!saw_eol) {
|
||||||
|
throw exception::eval_error("Two function definitions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||||
|
}
|
||||||
|
has_more = true;
|
||||||
|
retval = true;
|
||||||
|
saw_eol = true;
|
||||||
|
}
|
||||||
else if (Return()) {
|
else if (Return()) {
|
||||||
if (!saw_eol) {
|
if (!saw_eol) {
|
||||||
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
throw exception::eval_error("Two expressions missing line separator", File_Position(prev_line, prev_col), *m_filename);
|
||||||
|
22
unittests/switch_break.chai
Normal file
22
unittests/switch_break.chai
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
var total = 0;
|
||||||
|
|
||||||
|
switch(2) {
|
||||||
|
case (1) {
|
||||||
|
total += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
total += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (4) {
|
||||||
|
total += 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 2)
|
18
unittests/switch_default.chai
Normal file
18
unittests/switch_default.chai
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
var total = 0;
|
||||||
|
|
||||||
|
switch(2) {
|
||||||
|
case (1) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4;
|
||||||
|
}
|
||||||
|
case (4) {
|
||||||
|
total += 8;
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
total += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 16)
|
18
unittests/switch_fallthru.chai
Normal file
18
unittests/switch_fallthru.chai
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
var total = 0;
|
||||||
|
|
||||||
|
switch(2) {
|
||||||
|
case (1) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
total += 2;
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4;
|
||||||
|
}
|
||||||
|
case (4) {
|
||||||
|
total += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 14);
|
19
unittests/switch_fallthru_and_break.chai
Normal file
19
unittests/switch_fallthru_and_break.chai
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
var total = 0;
|
||||||
|
|
||||||
|
switch(2) {
|
||||||
|
case (1) {
|
||||||
|
total += 1;
|
||||||
|
}
|
||||||
|
case (2) {
|
||||||
|
total += 2;
|
||||||
|
}
|
||||||
|
case (3) {
|
||||||
|
total += 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case (4) {
|
||||||
|
total += 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_equal(total, 6)
|
Loading…
x
Reference in New Issue
Block a user