From 41e9027d9a8a0e8944900529b7ca2b44c9f79212 Mon Sep 17 00:00:00 2001 From: Jason Turner Date: Fri, 2 Oct 2015 11:45:28 -0600 Subject: [PATCH] Octal escape codes supported #211 --- CMakeLists.txt | 2 +- .../chaiscript/language/chaiscript_parser.hpp | 205 +++++++++++------- include/chaiscript/utility/json.hpp | 4 +- 3 files changed, 128 insertions(+), 83 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2380e06..07ae809 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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}) 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() add_definitions(-Wnoexcept) endif() diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 9e075ee..ebb8bfc 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -951,49 +951,88 @@ namespace chaiscript struct Char_Parser { + std::string &match; bool is_escaped; bool is_interpolated; bool saw_interpolation_marker; + bool is_octal; const bool interpolation_allowed; - Char_Parser(const bool t_interpolation_allowed) - : is_escaped(false), + std::string octal_matches; + + Char_Parser(std::string &t_match, const bool t_interpolation_allowed) + : match(t_match), + is_escaped(false), is_interpolated(false), saw_interpolation_marker(false), + is_octal(false), 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 (is_escaped) { - t_match.push_back('\\'); + match.push_back('\\'); is_escaped = false; } else { is_escaped = true; } } else { if (is_escaped) { - switch (t_char) { - case ('\'') : t_match.push_back('\''); break; - case ('\"') : t_match.push_back('\"'); break; - case ('?') : t_match.push_back('?'); break; - case ('a') : t_match.push_back('\a'); break; - case ('b') : t_match.push_back('\b'); break; - case ('f') : t_match.push_back('\f'); break; - case ('n') : t_match.push_back('\n'); break; - case ('r') : t_match.push_back('\r'); break; - case ('t') : t_match.push_back('\t'); break; - case ('v') : t_match.push_back('\v'); break; - case ('$') : t_match.push_back('$'); break; - default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename); + bool is_octal_char = t_char >= '0' && t_char <= '7'; + + if (is_octal) { + if (is_octal_char) { + octal_matches.push_back(t_char); + + if (octal_matches.size() == 3) { + process_octal(); + } + } else { + process_octal(); + match.push_back(t_char); + } + } 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 == '$') { saw_interpolation_marker = true; } else { - t_match.push_back(t_char); + match.push_back(t_char); } - is_escaped = false; } } @@ -1011,73 +1050,77 @@ namespace chaiscript if (Quoted_String_()) { std::string match; - - Char_Parser cparser(true); - 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) { - //If we've seen previous interpolation, add on instead of making a new one - m_match_stack.push_back(make_node(match, start.line, start.col)); + auto s = start + 1, end = m_position - 1; - build_match(prev_stack_top, "+"); - } else { - m_match_stack.push_back(make_node(match, start.line, start.col)); - } + while (s != end) { + if (cparser.saw_interpolation_marker) { + if (*s == '{') { + //We've found an interpolation point - //We've finished with the part of the string up to this point, so clear it - match.clear(); + if (cparser.is_interpolated) { + //If we've seen previous interpolation, add on instead of making a new one + m_match_stack.push_back(make_node(match, start.line, start.col)); - 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("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(prev_stack_top, "+"); + } else { + m_match_stack.push_back(make_node(match, start.line, start.col)); } - build_match(ev_stack_top); - build_match(tostr_stack_top); - build_match(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; - } - } + //We've finished with the part of the string up to this point, so clear it + match.clear(); - 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("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(ev_stack_top); + build_match(tostr_stack_top); + build_match(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(match, start.line, start.col)); build_match(prev_stack_top, "+"); @@ -1129,10 +1172,14 @@ namespace chaiscript const auto start = m_position; if (Single_Quoted_String_()) { 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(match, start.line, start.col)); diff --git a/include/chaiscript/utility/json.hpp b/include/chaiscript/utility/json.hpp index e8cae19..e5ba4f7 100644 --- a/include/chaiscript/utility/json.hpp +++ b/include/chaiscript/utility/json.hpp @@ -384,8 +384,6 @@ class JSON return std::to_string( Internal.Int ); case Class::Boolean: return Internal.Bool ? "true" : "false"; - default: - return ""; } } @@ -548,7 +546,7 @@ namespace { JSON parse_number( const string &str, size_t &offset ) { JSON Number; string val, exp_str; - char c; + char c = '\0'; bool isDouble = false; long exp = 0; for (; offset < str.size() ;) {