diff options
-rw-r--r-- | ChangeLog | 3 | ||||
-rw-r--r-- | src/reader.c | 111 | ||||
-rw-r--r-- | tests/test-list-subject.out | 1 | ||||
-rw-r--r-- | tests/test-list-subject.ttl | 3 |
4 files changed, 57 insertions, 61 deletions
@@ -24,7 +24,8 @@ serd (UNRELEASED) unstable; urgency=low * Add serd_node_new_blob and serd_base64_decode for handling arbitrary binary data via base64 encoding. * Support compilation as C++ under MSVC++. - * Impement pretty-printing for collections. + * Implement pretty-printing for collections. + * Use iterative algorithm for collection parsing. -- David Robillard <d@drobilla.net> (UNRELEASED) diff --git a/src/reader.c b/src/reader.c index 38d0c21a..e2eda76c 100644 --- a/src/reader.c +++ b/src/reader.c @@ -601,18 +601,35 @@ read_ws(SerdReader* reader) } } -static inline void +static inline bool read_ws_star(SerdReader* reader) { while (read_ws(reader)) {} + return true; } static inline bool read_ws_plus(SerdReader* reader) { TRY_RET(read_ws(reader)); + return read_ws_star(reader); +} + +static inline bool +peek_delim(SerdReader* reader, const char delim) +{ read_ws_star(reader); - return true; + return peek_byte(reader) == delim; +} + +static inline bool +eat_delim(SerdReader* reader, const char delim) +{ + if (peek_delim(reader, delim)) { + eat_byte_safe(reader, delim); + return read_ws_star(reader); + } + return false; } // [37] longString ::= #x22 #x22 #x22 lcharacter* #x22 #x22 #x22 @@ -1015,9 +1032,7 @@ read_blank(SerdReader* reader, ReadContext ctx, bool subject, Ref* dest) return true; case '[': eat_byte_safe(reader, '['); - read_ws_star(reader); - - const bool empty = (peek_byte(reader) == ']'); + const bool empty = peek_delim(reader, ']'); if (empty) { *ctx.flags |= (subject) ? SERD_EMPTY_S : SERD_EMPTY_O; } else { @@ -1140,12 +1155,8 @@ static bool read_objectList(SerdReader* reader, ReadContext ctx) { TRY_RET(read_object(reader, ctx)); - read_ws_star(reader); - while (peek_byte(reader) == ',') { - eat_byte_safe(reader, ','); - read_ws_star(reader); + while (eat_delim(reader, ',')) { TRY_RET(read_object(reader, ctx)); - read_ws_star(reader); } return true; } @@ -1164,10 +1175,7 @@ read_predicateObjectList(SerdReader* reader, ReadContext ctx) TRY_THROW(read_objectList(reader, ctx)); pop_node(reader, predicate); predicate = 0; - read_ws_star(reader); - while (peek_byte(reader) == ';') { - eat_byte_safe(reader, ';'); - read_ws_star(reader); + while (eat_delim(reader, ';')) { switch (peek_byte(reader)) { case '.': case ']': return true; @@ -1178,7 +1186,6 @@ read_predicateObjectList(SerdReader* reader, ReadContext ctx) TRY_THROW(read_objectList(reader, ctx)); pop_node(reader, predicate); predicate = 0; - read_ws_star(reader); } } pop_node(reader, predicate); @@ -1188,63 +1195,49 @@ except: return false; } -/** Recursive helper for read_collection. */ -static bool -read_collection_rec(SerdReader* reader, ReadContext ctx) -{ - read_ws_star(reader); - const bool end = (peek_byte(reader) == ')'); - const Ref rest = (end ? reader->rdf_nil : blank_id(reader)); - *ctx.flags |= SERD_LIST_CONT; - TRY_RET(emit_statement(reader, ctx.flags, ctx.graph, - ctx.subject, reader->rdf_rest, rest, 0, 0)); - - if (end) { - eat_byte_safe(reader, ')'); - } else { - ctx.subject = rest; - ctx.predicate = reader->rdf_first; - if (read_object(reader, ctx)) { - TRY_RET(read_collection_rec(reader, ctx)); - } - } - *ctx.flags &= ~SERD_LIST_CONT; - return true; -} - // [22] itemList ::= object+ // [23] collection ::= '(' itemList? ')' static bool read_collection(SerdReader* reader, ReadContext ctx, Ref* dest) { eat_byte_safe(reader, '('); - read_ws_star(reader); + bool end = peek_delim(reader, ')'); + *dest = end ? reader->rdf_nil : blank_id(reader); + if (ctx.subject) { + // subject predicate _:head + *ctx.flags |= (end ? 0 : SERD_LIST_O_BEGIN); + TRY_RET(emit_statement(reader, ctx.flags, ctx.graph, + ctx.subject, ctx.predicate, *dest, 0, 0)); + *ctx.flags |= SERD_LIST_CONT; + } else { + *ctx.flags |= (end ? 0 : SERD_LIST_S_BEGIN); + } - if (peek_byte(reader) == ')') { - *dest = reader->rdf_nil; - if (ctx.subject) { - TRY_RET(emit_statement(reader, ctx.flags, ctx.graph, - ctx.subject, ctx.predicate, *dest, 0, 0)); + ctx.subject = *dest; + while (!end) { + // _:node rdf:first object + ctx.predicate = reader->rdf_first; + if (!read_object(reader, ctx)) { + return error(reader, "unexpected end of collection\n"); } - eat_byte_safe(reader, ')'); - return true; - } - *dest = blank_id(reader); - *ctx.flags |= (!ctx.subject) ? SERD_LIST_S_BEGIN : SERD_LIST_O_BEGIN; + end = peek_delim(reader, ')'); - if (ctx.subject) { + // _:node rdf:rest _:rest + const Ref rest = end ? reader->rdf_nil : blank_id(reader); + *ctx.flags |= SERD_LIST_CONT; TRY_RET(emit_statement(reader, ctx.flags, ctx.graph, - ctx.subject, ctx.predicate, *dest, 0, 0)); - *ctx.flags = SERD_LIST_CONT; - } - ctx.subject = *dest; - ctx.predicate = reader->rdf_first; - if (!read_object(reader, ctx)) { - return error(reader, "unexpected end of collection\n"); + ctx.subject, reader->rdf_rest, rest, 0, 0)); + + ctx.subject = rest; + *ctx.flags |= SERD_LIST_CONT; + end = peek_delim(reader, ')'); } - return read_collection_rec(reader, ctx); + eat_byte_safe(reader, ')'); + + *ctx.flags &= ~SERD_LIST_CONT; + return true; } // [11] subject ::= resource | blank diff --git a/tests/test-list-subject.out b/tests/test-list-subject.out index e0e7f497..9a853774 100644 --- a/tests/test-list-subject.out +++ b/tests/test-list-subject.out @@ -1,3 +1,4 @@ +<http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/List> . _:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "apple" . _:genid1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:genid2 . _:genid2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "banana" . diff --git a/tests/test-list-subject.ttl b/tests/test-list-subject.ttl index 624336ae..5cd81dfb 100644 --- a/tests/test-list-subject.ttl +++ b/tests/test-list-subject.ttl @@ -1 +1,2 @@ -("apple" "banana") a <http://example.org/List> .
\ No newline at end of file +() a <http://example.org/List> . +("apple" "banana") a <http://example.org/List> . |