Commit 6d172713 authored by Jelte Jansen's avatar Jelte Jansen

create_from_string now throws a ParseError exception instead of returning an empty shared pointer

keep track of position when parsing a string, for better error feedback, for example when using files


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/jelte-datadef@290 e5f2f494-b856-4b98-b285-d166d9295462
parent 7ad75772
......@@ -27,6 +27,13 @@ std::ostream& operator <<(std::ostream &out, const ISC::Data::ElementPtr& e) {
return out << e->str();
}
const char*
ParseError::what() const throw() {
stringstream ss;
ss << msg << " line " << line << " pos " << pos;
return ss.str().c_str();
}
//
// factory functions
//
......@@ -64,7 +71,6 @@ ElementPtr
Element::create(const bool b)
{
try {
cout << "creating boolelement" << endl;
return ElementPtr(new BoolElement(b));
} catch (std::bad_alloc) {
return ElementPtr();
......@@ -109,83 +115,113 @@ char_in(char c, const char *chars)
}
static void
skip_chars(std::stringstream &in, const char *chars)
skip_chars(std::istream &in, const char *chars, int& line, int& pos)
{
char c = in.peek();
while (char_in(c, chars) && c != EOF) {
if (c == '\n') {
line++;
pos = 1;
} else {
pos++;
}
in.get();
c = in.peek();
}
}
/*static void
skip_chars(std::istream &in, const char *chars)
{
int l = 0, p = 0;
skip_chars(in, chars, l, p);
}*/
// skip on the input stream to one of the characters in chars
// if another character is found this function returns false
// unles that character is specified in the optional may_skip
//
// the character found is left on the stream
static bool
skip_to(std::stringstream &in, const char *chars, const char *may_skip="")
static void
skip_to(std::istream &in, int& line, int& pos, const char* chars, const char* may_skip="")
{
char c = in.get();
pos++;
while (c != EOF) {
if (c == '\n') {
pos = 1;
line++;
}
if (char_in(c, may_skip)) {
c = in.get();
pos++;
} else if (char_in(c, chars)) {
while(char_in(in.peek(), may_skip)) {
if (in.peek() == '\n') {
pos = 1;
line++;
}
in.get();
pos++;
}
in.putback(c);
return true;
pos--;
return;
} else {
// TODO: provide feeback mechanism?
cout << "error, '" << c << "' read; one of \"" << chars << "\" expected" << endl;
in.putback(c);
return false;
throw ParseError(std::string("'") + c + "' read, one of \"" + chars + "\" expected", line, pos);
}
}
// TODO: provide feeback mechanism?
cout << "error, EOF read; one of \"" << chars << "\" expected" << endl;
in.putback(c);
return false;
throw ParseError(std::string("EOF read, one of \"") + chars + "\" expected", line, pos);
}
/*static bool
skip_to(std::istream &in, const char *chars, const char *may_skip="") {
int line = 0, pos = 0;
return skip_to(in, line, pos, chars, may_skip);
}*/
static std::string
str_from_stringstream(std::stringstream &in)
str_from_stringstream(std::istream &in, int& line, int& pos) throw (ParseError)
{
char c = 0;
std::stringstream ss;
c = in.get();
pos++;
if (c == '"') {
c = in.get();
pos++;
} else {
return "badstring";
throw ParseError("String expected", line, pos);
}
while (c != EOF && c != '"') {
ss << c;
if (c == '\\' && in.peek() == '"') {
ss << in.get();
pos++;
}
c = in.get();
pos++;
}
return ss.str();
}
static std::string
word_from_stringstream(std::stringstream &in)
word_from_stringstream(std::istream &in, int& line, int& pos)
{
std::stringstream ss;
while (isalpha(in.peek())) {
ss << (char) in.get();
}
pos += ss.str().size();
return ss.str();
}
static ElementPtr
from_stringstream_int_or_double(std::stringstream &in)
from_stringstream_int_or_double(std::istream &in, int &line, int &pos)
{
int i;
in >> i;
// TODO count pos
if (in.peek() == '.') {
double d;
in >> d;
......@@ -197,9 +233,9 @@ from_stringstream_int_or_double(std::stringstream &in)
}
static ElementPtr
from_stringstream_bool(std::stringstream &in)
from_stringstream_bool(std::istream &in, int& line, int& pos)
{
std::string word = word_from_stringstream(in);
std::string word = word_from_stringstream(in, line, pos);
if (boost::iequals(word, "True")) {
return Element::create(true);
} else if (boost::iequals(word, "False")) {
......@@ -210,65 +246,78 @@ from_stringstream_bool(std::stringstream &in)
}
static ElementPtr
from_stringstream_string(std::stringstream &in)
from_stringstream_string(std::istream &in, int& line, int& pos)
{
return Element::create(str_from_stringstream(in));
return Element::create(str_from_stringstream(in, line, pos));
}
static ElementPtr
from_stringstream_list(std::stringstream &in)
from_stringstream_list(std::istream &in, int& line, int& pos)
{
char c = 0;
std::vector<ElementPtr> v;
ElementPtr cur_list_element;
//cout << "reading list at line " << line << " pos " << pos << endl;
skip_chars(in, " \t\n");
skip_chars(in, " \t\n", line, pos);
while (c != EOF && c != ']') {
cur_list_element = Element::create_from_string(in);
v.push_back(cur_list_element);
if (!skip_to(in, ",]", " \t\n")) {
return ElementPtr();
//cout << "at line " << line << " pos " << pos << " cur c: " << c << " next c: " << char(in.peek()) << endl;
if (in.peek() != ']') {
cur_list_element = Element::create_from_string(in, line, pos);
v.push_back(cur_list_element);
skip_to(in, line, pos, ",]", " \t\n");
}
c = in.get();
pos++;
}
return Element::create(v);
}
static ElementPtr
from_stringstream_map(std::stringstream &in)
from_stringstream_map(std::istream &in, int& line, int& pos)
{
char c = 0;
std::map<std::string, ElementPtr> m;
std::pair<std::string, ElementPtr> p;
std::string cur_map_key;
ElementPtr cur_map_element;
skip_chars(in, " \t\n");
skip_chars(in, " \t\n", line, pos);
while (c != EOF && c != '}') {
p.first = str_from_stringstream(in);
if (!skip_to(in, ":", " \t\n")) {
return ElementPtr();
} else {
// skip the :
in.get();
}
p.second = Element::create_from_string(in);
p.first = str_from_stringstream(in, line, pos);
skip_to(in, line, pos, ":", " \t\n");
// skip the :
in.get();
pos++;
p.second = Element::create_from_string(in, line, pos);
if (!p.second) { return ElementPtr(); };
m.insert(p);
skip_to(in, ",}", " \t\n");
skip_to(in, line, pos, ",}", " \t\n");
c = in.get();
pos++;
}
return Element::create(m);
}
//ElementPtr
//Element::create_from_string(std::stringstream &in)
ElementPtr
Element::create_from_string(std::stringstream &in)
Element::create_from_string(std::istream &in) throw(ParseError)
{
int line = 1, pos = 1;
return create_from_string(in, line, pos);
}
ElementPtr
Element::create_from_string(std::istream &in, int& line, int& pos) throw(ParseError)
{
char c = 0;
ElementPtr element;
bool el_read = false;
skip_chars(in, " \n\t");
skip_chars(in, " \n\t", line, pos);
while (c != EOF && !el_read) {
c = in.get();
pos++;
//std::cout << c << std::endl;
switch(c) {
case '1':
case '2':
......@@ -281,7 +330,7 @@ Element::create_from_string(std::stringstream &in)
case '9':
case '0':
in.putback(c);
element = from_stringstream_int_or_double(in);
element = from_stringstream_int_or_double(in, line, pos);
el_read = true;
break;
case 't':
......@@ -289,27 +338,26 @@ Element::create_from_string(std::stringstream &in)
case 'f':
case 'F':
in.putback(c);
element = from_stringstream_bool(in);
element = from_stringstream_bool(in, line, pos);
el_read = true;
break;
case '"':
in.putback('"');
element = from_stringstream_string(in);
element = from_stringstream_string(in, line, pos);
el_read = true;
break;
case '[':
element = from_stringstream_list(in);
element = from_stringstream_list(in, line, pos);
el_read = true;
break;
case '{':
element = from_stringstream_map(in);
element = from_stringstream_map(in, line, pos);
el_read = true;
break;
case EOF:
break;
default:
// TODO this might not be a fatal error
// provide feedback mechanism?
cout << "error: unexpected '" << c << "'" << endl;
return ElementPtr();
throw ParseError(std::string("error: unexpected character ") + c, line, pos);
break;
}
}
......@@ -317,7 +365,7 @@ Element::create_from_string(std::stringstream &in)
return element;
} else {
// throw exception?
return ElementPtr();
throw ParseError("nothing read");
}
}
......
......@@ -20,6 +20,17 @@ namespace ISC { namespace Data {
std::string msg;
};
class ParseError : public std::exception {
public:
ParseError(std::string m = "Parse error in element data", int l = 0, int p = 0) : msg(m), line(l), pos(p) {}
~ParseError() throw() {}
const char* what() const throw();
private:
std::string msg;
int line;
int pos;
};
class DecodeError : public std::exception {
public:
DecodeError(std::string m = "Wire-format data is invalid") : msg(m) {}
......@@ -145,8 +156,11 @@ namespace ISC { namespace Data {
// the memory could not be allocated
// example:
// ElementPtr my_element = Element::create_from_string("{\"foo\": [ 1, 2, false ] }");
static ElementPtr create_from_string(std::stringstream& in);
//static ElementPtr create_from_string(std::stringstream& in);
static ElementPtr create_from_string(const std::string& in);
static ElementPtr create_from_string(std::istream& in) throw(ParseError);
// make this one private?
static ElementPtr create_from_string(std::istream& in, int& line, int &pos) throw(ParseError);
//static ElementPtr create_from_xml(std::stringstream& in);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment