Octal escape codes supported #211

This commit is contained in:
Jason Turner
2015-10-02 11:45:28 -06:00
parent 8d9dc2b0a3
commit 41e9027d9a
3 changed files with 128 additions and 83 deletions

View File

@@ -174,7 +174,7 @@ else()
add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG}) add_definitions(-Wall -Wextra -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Wcast-qual -Wunused -Woverloaded-virtual -pedantic ${CPP11_FLAG})
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_definitions(-Weverything -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors) add_definitions(-Weverything -Wno-c++98-compat-pedantic -Wno-c++98-compat -Wno-documentation -Wno-switch-enum -Wno-weak-vtables -Wno-sign-conversion -Wno-missing-prototypes -Wno-padded -Wno-missing-noreturn -Wno-exit-time-destructors)
else() else()
add_definitions(-Wnoexcept) add_definitions(-Wnoexcept)
endif() endif()

View File

@@ -951,49 +951,88 @@ namespace chaiscript
struct Char_Parser struct Char_Parser
{ {
std::string &match;
bool is_escaped; bool is_escaped;
bool is_interpolated; bool is_interpolated;
bool saw_interpolation_marker; bool saw_interpolation_marker;
bool is_octal;
const bool interpolation_allowed; const bool interpolation_allowed;
Char_Parser(const bool t_interpolation_allowed) std::string octal_matches;
: is_escaped(false),
Char_Parser(std::string &t_match, const bool t_interpolation_allowed)
: match(t_match),
is_escaped(false),
is_interpolated(false), is_interpolated(false),
saw_interpolation_marker(false), saw_interpolation_marker(false),
is_octal(false),
interpolation_allowed(t_interpolation_allowed) interpolation_allowed(t_interpolation_allowed)
{ {
} }
void parse(std::string &t_match, const char t_char, const int line, const int col, const std::string &filename) { ~Char_Parser(){
if (is_octal) {
process_octal();
}
}
void process_octal()
{
int val = stoi(octal_matches, 0, 8);
match.push_back(char(val));
octal_matches.clear();
is_escaped = false;
is_octal = false;
}
void parse(const char t_char, const int line, const int col, const std::string &filename) {
if (t_char == '\\') { if (t_char == '\\') {
if (is_escaped) { if (is_escaped) {
t_match.push_back('\\'); match.push_back('\\');
is_escaped = false; is_escaped = false;
} else { } else {
is_escaped = true; is_escaped = true;
} }
} else { } else {
if (is_escaped) { if (is_escaped) {
switch (t_char) { bool is_octal_char = t_char >= '0' && t_char <= '7';
case ('\'') : t_match.push_back('\''); break;
case ('\"') : t_match.push_back('\"'); break; if (is_octal) {
case ('?') : t_match.push_back('?'); break; if (is_octal_char) {
case ('a') : t_match.push_back('\a'); break; octal_matches.push_back(t_char);
case ('b') : t_match.push_back('\b'); break;
case ('f') : t_match.push_back('\f'); break; if (octal_matches.size() == 3) {
case ('n') : t_match.push_back('\n'); break; process_octal();
case ('r') : t_match.push_back('\r'); break; }
case ('t') : t_match.push_back('\t'); break; } else {
case ('v') : t_match.push_back('\v'); break; process_octal();
case ('$') : t_match.push_back('$'); break; match.push_back(t_char);
default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); }
} else if (is_octal_char) {
is_octal = true;
octal_matches.push_back(t_char);
} else {
switch (t_char) {
case ('\'') : match.push_back('\''); break;
case ('\"') : match.push_back('\"'); break;
case ('?') : match.push_back('?'); break;
case ('a') : match.push_back('\a'); break;
case ('b') : match.push_back('\b'); break;
case ('f') : match.push_back('\f'); break;
case ('n') : match.push_back('\n'); break;
case ('r') : match.push_back('\r'); break;
case ('t') : match.push_back('\t'); break;
case ('v') : match.push_back('\v'); break;
case ('$') : match.push_back('$'); break;
default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename);
}
is_escaped = false;
} }
} else if (interpolation_allowed && t_char == '$') { } else if (interpolation_allowed && t_char == '$') {
saw_interpolation_marker = true; saw_interpolation_marker = true;
} else { } else {
t_match.push_back(t_char); match.push_back(t_char);
} }
is_escaped = false;
} }
} }
@@ -1011,73 +1050,77 @@ namespace chaiscript
if (Quoted_String_()) { if (Quoted_String_()) {
std::string match; std::string match;
Char_Parser cparser(true);
const auto prev_stack_top = m_match_stack.size(); const auto prev_stack_top = m_match_stack.size();
auto s = start + 1, end = m_position - 1; bool is_interpolated = [&]() {
Char_Parser cparser(match, true);
while (s != end) {
if (cparser.saw_interpolation_marker) {
if (*s == '{') {
//We've found an interpolation point
if (cparser.is_interpolated) { auto s = start + 1, end = m_position - 1;
//If we've seen previous interpolation, add on instead of making a new one
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+"); while (s != end) {
} else { if (cparser.saw_interpolation_marker) {
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col)); if (*s == '{') {
} //We've found an interpolation point
//We've finished with the part of the string up to this point, so clear it if (cparser.is_interpolated) {
match.clear(); //If we've seen previous interpolation, add on instead of making a new one
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
std::string eval_match; build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
} else {
++s; m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
while ((s != end) && (*s != '}')) {
eval_match.push_back(*s);
++s;
}
if (*s == '}') {
cparser.is_interpolated = true;
++s;
const auto tostr_stack_top = m_match_stack.size();
m_match_stack.push_back(make_node<eval::Id_AST_Node>("to_string", start.line, start.col));
const auto ev_stack_top = m_match_stack.size();
try {
ChaiScript_Parser parser;
parser.parse(eval_match, "instr eval");
m_match_stack.push_back(parser.ast());
} catch (const exception::eval_error &e) {
throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename);
} }
build_match<eval::Arg_List_AST_Node>(ev_stack_top); //We've finished with the part of the string up to this point, so clear it
build_match<eval::Fun_Call_AST_Node>(tostr_stack_top); match.clear();
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
} else {
throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename);
}
} else {
match.push_back('$');
}
cparser.saw_interpolation_marker = false;
} else {
cparser.parse(match, *s, start.line, start.col, *m_filename);
++s;
}
}
if (cparser.is_interpolated) { std::string eval_match;
++s;
while ((s != end) && (*s != '}')) {
eval_match.push_back(*s);
++s;
}
if (*s == '}') {
cparser.is_interpolated = true;
++s;
const auto tostr_stack_top = m_match_stack.size();
m_match_stack.push_back(make_node<eval::Id_AST_Node>("to_string", start.line, start.col));
const auto ev_stack_top = m_match_stack.size();
try {
ChaiScript_Parser parser;
parser.parse(eval_match, "instr eval");
m_match_stack.push_back(parser.ast());
} catch (const exception::eval_error &e) {
throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename);
}
build_match<eval::Arg_List_AST_Node>(ev_stack_top);
build_match<eval::Fun_Call_AST_Node>(tostr_stack_top);
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
} else {
throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename);
}
} else {
match.push_back('$');
}
cparser.saw_interpolation_marker = false;
} else {
cparser.parse(*s, start.line, start.col, *m_filename);
++s;
}
}
return cparser.is_interpolated;
}();
if (is_interpolated) {
m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col)); m_match_stack.push_back(make_node<eval::Quoted_String_AST_Node>(match, start.line, start.col));
build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+"); build_match<eval::Binary_Operator_AST_Node>(prev_stack_top, "+");
@@ -1129,10 +1172,14 @@ namespace chaiscript
const auto start = m_position; const auto start = m_position;
if (Single_Quoted_String_()) { if (Single_Quoted_String_()) {
std::string match; std::string match;
Char_Parser cparser(false);
for (auto s = start + 1, end = m_position - 1; s != end; ++s) { {
cparser.parse(match, *s, start.line, start.col, *m_filename); // scope for cparser destrutor
Char_Parser cparser(match, false);
for (auto s = start + 1, end = m_position - 1; s != end; ++s) {
cparser.parse(*s, start.line, start.col, *m_filename);
}
} }
m_match_stack.push_back(make_node<eval::Single_Quoted_String_AST_Node>(match, start.line, start.col)); m_match_stack.push_back(make_node<eval::Single_Quoted_String_AST_Node>(match, start.line, start.col));

View File

@@ -384,8 +384,6 @@ class JSON
return std::to_string( Internal.Int ); return std::to_string( Internal.Int );
case Class::Boolean: case Class::Boolean:
return Internal.Bool ? "true" : "false"; return Internal.Bool ? "true" : "false";
default:
return "";
} }
} }
@@ -548,7 +546,7 @@ namespace {
JSON parse_number( const string &str, size_t &offset ) { JSON parse_number( const string &str, size_t &offset ) {
JSON Number; JSON Number;
string val, exp_str; string val, exp_str;
char c; char c = '\0';
bool isDouble = false; bool isDouble = false;
long exp = 0; long exp = 0;
for (; offset < str.size() ;) { for (; offset < str.size() ;) {