aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-02-25 11:16:13 -0500
committerDavid Robillard <d@drobilla.net>2023-12-02 18:49:08 -0500
commit64024d0fa6a6dc048b2b846738846da597025f56 (patch)
tree7966dc76915aee1e4f284abe3685aa5b28e14dd3
parent456bdeef35ffbfbdad7609e8b8a4ef71372786fd (diff)
downloadserd-64024d0fa6a6dc048b2b846738846da597025f56.tar.gz
serd-64024d0fa6a6dc048b2b846738846da597025f56.tar.bz2
serd-64024d0fa6a6dc048b2b846738846da597025f56.zip
Leave statement caret at the start of literals
This allows a precise location to be reported for errors within literals, by adding the offset of the error in the literal to the caret. This will be used to report nice errors for things like regular expressions and supported XSD datatypes.
-rw-r--r--src/read_turtle.c5
-rw-r--r--src/reader.c17
-rw-r--r--src/reader.h7
-rw-r--r--test/test_reader.c56
4 files changed, 80 insertions, 5 deletions
diff --git a/src/read_turtle.c b/src/read_turtle.c
index 027f0918..c3970a1e 100644
--- a/src/read_turtle.c
+++ b/src/read_turtle.c
@@ -13,6 +13,7 @@
#include "try.h"
#include "turtle.h"
+#include "serd/caret.h"
#include "serd/node.h"
#include "serd/reader.h"
#include "serd/sink.h"
@@ -610,6 +611,7 @@ read_object(SerdReader* const reader,
bool* const ate_dot)
{
const size_t orig_stack_size = reader->stack.size;
+ SerdCaret orig_caret = reader->source->caret;
assert(ctx->subject);
@@ -660,6 +662,7 @@ read_object(SerdReader* const reader,
break;
case '\"':
case '\'':
+ ++orig_caret.col;
st = read_literal(reader, &o, ate_dot);
break;
default:
@@ -668,7 +671,7 @@ read_object(SerdReader* const reader,
}
if (!st && simple && o) {
- st = emit_statement(reader, *ctx, o);
+ st = emit_statement_at(reader, *ctx, o, &orig_caret);
}
serd_stack_pop_to(&reader->stack, orig_stack_size);
diff --git a/src/reader.c b/src/reader.c
index f34f7974..7e0864cc 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -162,9 +162,10 @@ tokcmp(const SerdNode* const node, const char* const tok, const size_t n)
}
SerdStatus
-emit_statement(SerdReader* const reader,
- const ReadContext ctx,
- SerdNode* const o)
+emit_statement_at(SerdReader* const reader,
+ const ReadContext ctx,
+ SerdNode* const o,
+ SerdCaret* const caret)
{
if (reader->stack.size + (2 * sizeof(SerdNode)) > reader->stack.buf_size) {
return SERD_BAD_STACK;
@@ -175,7 +176,7 @@ emit_statement(SerdReader* const reader,
serd_node_zero_pad(o);
const SerdStatement statement = {{ctx.subject, ctx.predicate, o, ctx.graph},
- &reader->source->caret};
+ caret};
const SerdStatus st =
serd_sink_write_statement(reader->sink, *ctx.flags, &statement);
@@ -185,6 +186,14 @@ emit_statement(SerdReader* const reader,
}
SerdStatus
+emit_statement(SerdReader* const reader,
+ const ReadContext ctx,
+ SerdNode* const o)
+{
+ return emit_statement_at(reader, ctx, o, &reader->source->caret);
+}
+
+SerdStatus
serd_reader_read_document(SerdReader* const reader)
{
assert(reader);
diff --git a/src/reader.h b/src/reader.h
index 601453b0..132d038e 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -10,6 +10,7 @@
#include "try.h"
#include "serd/attributes.h"
+#include "serd/caret.h"
#include "serd/node.h"
#include "serd/reader.h"
#include "serd/sink.h"
@@ -85,6 +86,12 @@ void
set_blank_id(SerdReader* reader, SerdNode* node, size_t buf_size);
SerdStatus
+emit_statement_at(SerdReader* reader,
+ ReadContext ctx,
+ SerdNode* o,
+ SerdCaret* caret);
+
+SerdStatus
emit_statement(SerdReader* reader, ReadContext ctx, SerdNode* o);
static inline int
diff --git a/test/test_reader.c b/test/test_reader.c
index dd090d83..b5cefbe1 100644
--- a/test/test_reader.c
+++ b/test/test_reader.c
@@ -3,12 +3,16 @@
#undef NDEBUG
+#include "serd/caret.h"
#include "serd/event.h"
#include "serd/input_stream.h"
+#include "serd/node.h"
#include "serd/reader.h"
#include "serd/sink.h"
+#include "serd/statement.h"
#include "serd/status.h"
#include "serd/stream.h"
+#include "serd/string_view.h"
#include "serd/syntax.h"
#include "serd/world.h"
#include "zix/allocator.h"
@@ -21,6 +25,7 @@
#endif
#include <assert.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
@@ -486,6 +491,56 @@ test_read_empty(const char* const path)
serd_world_free(world);
}
+static SerdStatus
+check_cursor(void* handle, const SerdEvent* event)
+{
+ bool* const called = (bool*)handle;
+
+ if (event->type == SERD_STATEMENT) {
+ const SerdCaret* const caret =
+ serd_statement_caret(event->statement.statement);
+ assert(caret);
+
+ assert(!strcmp(serd_node_string(serd_caret_document(caret)), "string"));
+ assert(serd_caret_line(caret) == 1);
+ assert(serd_caret_column(caret) == 47);
+ }
+
+ *called = true;
+ return SERD_SUCCESS;
+}
+
+static void
+test_error_cursor(void)
+{
+ SerdWorld* world = serd_world_new();
+ bool called = false;
+ SerdSink* sink = serd_sink_new(&called, check_cursor, NULL);
+ SerdReader* const reader = serd_reader_new(world, SERD_TURTLE, 0, sink);
+ assert(sink);
+ assert(reader);
+
+ static const char* const string =
+ "<http://example.org/s> <http://example.org/p> "
+ "<http://example.org/o> .";
+
+ SerdNode* const string_name = serd_new_string(serd_string("string"));
+ const char* position = string;
+ SerdInputStream in = serd_open_input_string(&position);
+
+ SerdStatus st = serd_reader_start(reader, &in, string_name, 1);
+ assert(!st);
+ assert(serd_reader_read_document(reader) == SERD_SUCCESS);
+ assert(!serd_reader_finish(reader));
+ assert(called);
+ assert(!serd_close_input(&in));
+
+ serd_node_free(string_name);
+ serd_reader_free(reader);
+ serd_sink_free(sink);
+ serd_world_free(world);
+}
+
int
main(void)
{
@@ -504,6 +559,7 @@ main(void)
test_read_nquads_chunks(nq_path);
test_read_turtle_chunks(ttl_path);
test_read_empty(ttl_path);
+ test_error_cursor();
assert(!zix_remove(dir));