aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-02-25 11:16:13 -0500
committerDavid Robillard <d@drobilla.net>2022-01-14 19:37:51 -0500
commit4436f80225c441a878c4baf856d21dee0394c8dc (patch)
tree707757fd8544595a8c6fa423c72e7a5fe5c2d6be
parent17003e707a3368a029dd8c0e7bdf98979f691daf (diff)
downloadserd-4436f80225c441a878c4baf856d21dee0394c8dc.tar.gz
serd-4436f80225c441a878c4baf856d21dee0394c8dc.tar.bz2
serd-4436f80225c441a878c4baf856d21dee0394c8dc.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/n3.c5
-rw-r--r--src/reader.c17
-rw-r--r--src/reader.h6
-rw-r--r--test/test_reader.c50
4 files changed, 73 insertions, 5 deletions
diff --git a/src/n3.c b/src/n3.c
index 80c7b9fe..5940c010 100644
--- a/src/n3.c
+++ b/src/n3.c
@@ -15,6 +15,7 @@
*/
#include "byte_source.h"
+#include "caret.h"
#include "env.h"
#include "namespaces.h"
#include "node.h"
@@ -732,6 +733,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);
@@ -782,6 +784,7 @@ read_object(SerdReader* const reader,
break;
case '\"':
case '\'':
+ ++orig_caret.col;
st = read_literal(reader, &o, ate_dot);
break;
default:
@@ -790,7 +793,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 6ce40452..5afc28ff 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -154,9 +154,10 @@ push_node(SerdReader* const reader,
}
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_ERR_OVERFLOW;
@@ -167,7 +168,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);
@@ -176,6 +177,14 @@ emit_statement(SerdReader* const reader,
return st;
}
+SerdStatus
+emit_statement(SerdReader* const reader,
+ const ReadContext ctx,
+ SerdNode* const o)
+{
+ return emit_statement_at(reader, ctx, o, &reader->source->caret);
+}
+
static SerdStatus
read_statement(SerdReader* const reader)
{
diff --git a/src/reader.h b/src/reader.h
index 30fd69a9..23d38009 100644
--- a/src/reader.h
+++ b/src/reader.h
@@ -95,6 +95,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);
SerdStatus
diff --git a/test/test_reader.c b/test/test_reader.c
index 3651e014..32b475f9 100644
--- a/test/test_reader.c
+++ b/test/test_reader.c
@@ -368,6 +368,55 @@ test_read_empty(void)
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_name(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);
+ SerdEnv* const env = serd_env_new(SERD_EMPTY_STRING());
+ SerdReader* const reader =
+ serd_reader_new(world, SERD_TURTLE, 0, env, sink, 4096);
+
+ assert(sink);
+ assert(reader);
+
+ SerdByteSource* byte_source =
+ serd_byte_source_new_string("<http://example.org/s> <http://example.org/p> "
+ "<http://example.org/o> .",
+ NULL);
+
+ SerdStatus st = serd_reader_start(reader, byte_source);
+ assert(!st);
+ assert(serd_reader_read_document(reader) == SERD_SUCCESS);
+ assert(called);
+
+ serd_byte_source_free(byte_source);
+ serd_reader_free(reader);
+ serd_env_free(env);
+ serd_sink_free(sink);
+ serd_world_free(world);
+}
+
int
main(void)
{
@@ -377,5 +426,6 @@ main(void)
test_read_eof_by_byte();
test_read_chunks();
test_read_empty();
+ test_error_cursor();
return 0;
}