diff options
-rw-r--r-- | src/writer.c | 252 | ||||
-rw-r--r-- | test/test_reader_writer.c | 2 |
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) { |