aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog3
-rw-r--r--src/reader.c111
-rw-r--r--tests/test-list-subject.out1
-rw-r--r--tests/test-list-subject.ttl3
4 files changed, 57 insertions, 61 deletions
diff --git a/ChangeLog b/ChangeLog
index 3931764a..e6847960 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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> .