aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/writer.c252
-rw-r--r--test/test_reader_writer.c2
2 files changed, 175 insertions, 79 deletions
diff --git a/src/writer.c b/src/writer.c
index a1d91ff8..6dd59c8e 100644
--- a/src/writer.c
+++ b/src/writer.c
@@ -994,75 +994,118 @@ terminate_context(SerdWriter* writer)
}
SERD_NODISCARD static SerdStatus
-serd_writer_write_statement(SerdWriter* const writer,
- const SerdStatementFlags flags,
- const SerdStatement* const statement)
+write_ntriples_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object)
{
- assert(!((flags & SERD_ANON_S) && (flags & SERD_LIST_S)));
- assert(!((flags & SERD_EMPTY_S) && (flags & SERD_LIST_S)));
- assert(!((flags & SERD_ANON_O) && (flags & SERD_LIST_O)));
- assert(!((flags & SERD_EMPTY_O) && (flags & SERD_LIST_O)));
+ SerdStatus st = SERD_SUCCESS;
- if (writer->syntax == SERD_SYNTAX_EMPTY) {
- return SERD_SUCCESS;
+ TRY(st, write_node(writer, subject, SERD_SUBJECT, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, predicate, SERD_PREDICATE, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, object, SERD_OBJECT, flags));
+ TRY(st, esink(" .\n", 3, writer));
+
+ return st;
+}
+
+static SerdStatus
+write_nquads_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph)
+{
+ SerdStatus st = SERD_SUCCESS;
+
+ TRY(st, write_node(writer, subject, SERD_SUBJECT, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, predicate, SERD_PREDICATE, flags));
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, object, SERD_OBJECT, flags));
+
+ if (graph) {
+ TRY(st, esink(" ", 1, writer));
+ TRY(st, write_node(writer, graph, SERD_GRAPH, flags));
}
- SerdStatus st = SERD_SUCCESS;
- const SerdNode* const subject = serd_statement_subject(statement);
- const SerdNode* const predicate = serd_statement_predicate(statement);
- const SerdNode* const object = serd_statement_object(statement);
- const SerdNode* const graph = serd_statement_graph(statement);
+ return esink(" .\n", 3, writer);
+}
- if (!is_resource(subject) || !is_resource(predicate) || !object ||
- ((flags & SERD_ANON_S) && (flags & SERD_LIST_S)) || // Nonsense
- ((flags & SERD_ANON_O) && (flags & SERD_LIST_O)) || // Nonsense
- ((flags & SERD_ANON_S) && (flags & SERD_TERSE_S)) || // Unsupported
- ((flags & SERD_ANON_O) && (flags & SERD_TERSE_O))) { // Unsupported
- return SERD_BAD_ARG;
+static SerdStatus
+update_abbreviation_context(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph)
+{
+ SerdStatus st = SERD_SUCCESS;
+
+ // Push context for anonymous or list subject if necessary
+ if (flags & SERD_ANON_S) {
+ st = push_context(writer, CTX_BLANK, flags, graph, subject, predicate);
+ } else if (flags & SERD_LIST_S) {
+ st = push_context(writer, CTX_LIST, flags, graph, subject, NULL);
}
- // Simple case: write a line of NTriples or NQuads
- if (writer->syntax == SERD_NTRIPLES || writer->syntax == SERD_NQUADS) {
- TRY(st, write_node(writer, subject, SERD_SUBJECT, flags));
- TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, predicate, SERD_PREDICATE, flags));
- TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, object, SERD_OBJECT, flags));
- if (writer->syntax == SERD_NQUADS && graph) {
- TRY(st, esink(" ", 1, writer));
- TRY(st, write_node(writer, graph, SERD_GRAPH, flags));
+ // Push context for list or anonymous object if necessary
+ if (!st) {
+ if (flags & SERD_ANON_O) {
+ st = push_context(writer, CTX_BLANK, flags, graph, object, NULL);
+ } else if (flags & SERD_LIST_O) {
+ st = push_context(writer, CTX_LIST, flags, graph, object, NULL);
}
- TRY(st, esink(" .\n", 3, writer));
- return SERD_SUCCESS;
}
- // Separate graphs if necessary
- if ((graph && !serd_node_equals(graph, writer->context.graph)) ||
- (!graph && ctx(writer, SERD_GRAPH))) {
- TRY(st, terminate_context(writer));
- reset_context(writer, RESET_GRAPH | RESET_INDENT);
- if (graph) {
- TRY(st, write_top_level_sep(writer));
- TRY(st, write_node(writer, graph, SERD_GRAPH, flags));
- TRY(st, write_sep(writer, flags, SEP_GRAPH_BEGIN));
- serd_node_set(&writer->context.graph, graph);
- }
+ return st;
+}
+
+SERD_NODISCARD static SerdStatus
+write_list_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph)
+{
+ SerdStatus st = SERD_SUCCESS;
+
+ if (!strcmp(serd_node_string(predicate), NS_RDF "first") &&
+ !strcmp(serd_node_string(object), NS_RDF "nil")) {
+ return esink("()", 2, writer);
}
- if (writer->context.type == CTX_LIST) {
- // Continue a list
- if (!strcmp(serd_node_string(predicate), NS_RDF "first") &&
- !strcmp(serd_node_string(object), NS_RDF "nil")) {
- return esink("()", 2, writer);
- }
+ TRY_FAILING(st, write_list_next(writer, flags, predicate, object));
+ if (st == SERD_FAILURE) {
+ pop_context(writer);
+ return SERD_SUCCESS;
+ }
- TRY_FAILING(st, write_list_next(writer, flags, predicate, object));
- if (st == SERD_FAILURE) { // Reached end of list
- pop_context(writer);
- return SERD_SUCCESS;
- }
+ return update_abbreviation_context(
+ writer, flags, subject, predicate, object, graph);
+}
+
+SERD_NODISCARD static SerdStatus
+write_turtle_trig_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph)
+{
+ SerdStatus st = SERD_SUCCESS;
+
+ if (writer->context.type == CTX_LIST) {
+ return write_list_statement(
+ writer, flags, subject, predicate, object, graph);
+ }
- } else if (serd_node_equals(subject, writer->context.subject)) {
+ if (serd_node_equals(subject, writer->context.subject)) {
if (serd_node_equals(predicate, writer->context.predicate)) {
// Elide S P (write O)
@@ -1091,8 +1134,6 @@ serd_writer_write_statement(SerdWriter* const writer,
TRY(st, write_pred(writer, flags, predicate));
}
- TRY(st, write_node(writer, object, SERD_OBJECT, flags));
-
} else {
// No abbreviation
@@ -1118,34 +1159,89 @@ serd_writer_write_statement(SerdWriter* const writer,
if (!(flags & SERD_LIST_S)) {
TRY(st, write_pred(writer, flags, predicate));
}
+ }
- TRY(st, write_node(writer, object, SERD_OBJECT, flags));
+ TRY(st, write_node(writer, object, SERD_OBJECT, flags));
+
+ return update_abbreviation_context(
+ writer, flags, subject, predicate, object, graph);
+}
+
+SERD_NODISCARD static SerdStatus
+write_turtle_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object)
+{
+ return write_turtle_trig_statement(
+ writer, flags, subject, predicate, object, NULL);
+}
+
+SERD_NODISCARD static SerdStatus
+write_trig_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdNode* const subject,
+ const SerdNode* const predicate,
+ const SerdNode* const object,
+ const SerdNode* const graph)
+{
+ SerdStatus st = SERD_SUCCESS;
+
+ if (!serd_node_equals(graph, writer->context.graph)) {
+ TRY(st, terminate_context(writer));
+ TRY(st, write_top_level_sep(writer));
+ reset_context(writer, true);
+
+ if (graph) {
+ TRY(st, write_node(writer, graph, SERD_GRAPH, flags));
+ TRY(st, write_sep(writer, flags, SEP_GRAPH_BEGIN));
+ serd_node_set(&writer->context.graph, graph);
+ }
}
- if (flags & (SERD_ANON_S | SERD_LIST_S)) {
- // Push context for anonymous or list subject
- const bool is_list = (flags & SERD_LIST_S);
- TRY(st,
- push_context(writer,
- is_list ? CTX_LIST : CTX_BLANK,
- flags,
- graph,
- subject,
- is_list ? NULL : predicate));
+ return write_turtle_trig_statement(
+ writer, flags, subject, predicate, object, graph);
+}
+
+SERD_NODISCARD static SerdStatus
+serd_writer_write_statement(SerdWriter* const writer,
+ const SerdStatementFlags flags,
+ const SerdStatement* const statement)
+{
+ const SerdNode* const subject = serd_statement_subject(statement);
+ const SerdNode* const predicate = serd_statement_predicate(statement);
+ const SerdNode* const object = serd_statement_object(statement);
+ const SerdNode* const graph = serd_statement_graph(statement);
+
+ if (!is_resource(subject) || !is_resource(predicate) || !object ||
+ ((flags & SERD_ANON_S) && (flags & SERD_LIST_S)) || // Nonsense
+ ((flags & SERD_ANON_O) && (flags & SERD_LIST_O)) || // Nonsense
+ ((flags & SERD_ANON_S) && (flags & SERD_TERSE_S)) || // Unsupported
+ ((flags & SERD_ANON_O) && (flags & SERD_TERSE_O))) { // Unsupported
+ return SERD_BAD_ARG;
}
- if (flags & (SERD_ANON_O | SERD_LIST_O)) {
- // Push context for anonymous or list object if necessary
- TRY(st,
- push_context(writer,
- (flags & SERD_LIST_O) ? CTX_LIST : CTX_BLANK,
- flags,
- graph,
- object,
- NULL));
+ switch (writer->syntax) {
+ case SERD_SYNTAX_EMPTY:
+ break;
+
+ case SERD_TURTLE:
+ return write_turtle_statement(writer, flags, subject, predicate, object);
+
+ case SERD_NTRIPLES:
+ return write_ntriples_statement(writer, flags, subject, predicate, object);
+
+ case SERD_NQUADS:
+ return write_nquads_statement(
+ writer, flags, subject, predicate, object, graph);
+
+ case SERD_TRIG:
+ return write_trig_statement(
+ writer, flags, subject, predicate, object, graph);
}
- return st;
+ return SERD_SUCCESS;
}
SERD_NODISCARD static SerdStatus
diff --git a/test/test_reader_writer.c b/test/test_reader_writer.c
index fd9c0d28..324135a4 100644
--- a/test/test_reader_writer.c
+++ b/test/test_reader_writer.c
@@ -373,7 +373,7 @@ test_write_errors(void)
SerdWorld* const world = serd_world_new();
ErrorContext ctx = {0U, 0U};
- const size_t max_offsets[] = {0, 386, 1911, 2003, 386};
+ const size_t max_offsets[] = {0, 373, 1911, 2003, 414};
// Test errors at different offsets to hit different code paths
for (unsigned s = 1; s <= (unsigned)SERD_TRIG; ++s) {