diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/config.h | 15 | ||||
-rw-r--r-- | src/core/state.c | 69 | ||||
-rw-r--r-- | src/core/state.h | 9 | ||||
-rw-r--r-- | src/core/utils.h | 13 |
4 files changed, 101 insertions, 5 deletions
diff --git a/src/core/config.h b/src/core/config.h index 389a146..63b131b 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -5,11 +5,26 @@ // not opaque) type which the consumer of the core library is supposed to // assemble themselves. It contains hooks which the State will use for all effects. +#include "location.h" + +#include <stddef.h> + // This handler is used for output from the user-supplied actual program. typedef void (* SandPrintHandler)(const char *message, size_t length); +typedef enum { + SAND_DIAGNOSTIC_INFO, + SAND_DIAGNOSTIC_WARNING, + SAND_DIAGNOSTIC_ERROR, +} SandDiagnosticLevel; + +// This handler is used when the implementation has a report to make. +// These could for example be displayed in tan editor's interface. +typedef void (* SandDiagnosticHandler)(const SandLocation *, SandDiagnosticLevel, const char *message, size_t message_length); + typedef struct { SandPrintHandler print_handler; + SandDiagnosticHandler diagnostic_handler; } SandConfig; #endif diff --git a/src/core/state.c b/src/core/state.c index 91bd9e4..18448eb 100644 --- a/src/core/state.c +++ b/src/core/state.c @@ -1,9 +1,72 @@ #include "state.h" +#include "std_allocator.h" + +#include <assert.h> +#include <stdarg.h> SandState sand_create_state(SandConfig config) { - return (SandState) { - .config = config, - }; + SandState S; + + S.config = config; + S.gpa = sand_get_std_allocator(); + + return S; +} + +char *sand_vasprintf(SandAllocator *a, size_t *length_out, const char *fmt, va_list ap) { + va_list ap_clone; + + va_copy(ap_clone, ap); + int length = vsnprintf(NULL, 0, fmt, ap_clone); + va_end(ap_clone); + if (length < 0) { + goto fail; + } + + char *buffer = sand_allocate(a, length + 1); // Include NUL character. + if (buffer == NULL) { + goto fail; + } + + va_copy(ap_clone, ap); + int final_length = vsnprintf(buffer, length + 1, fmt, ap_clone); + va_end(ap_clone); + assert(final_length == length); + + if (length_out != NULL) { + *length_out = length; + } + return buffer; + +fail: + if (length_out != NULL) { + *length_out = 0; + } + return NULL; +} + +_SAND_FORMAT_ATTR(printf, 3, 4) +char *sand_asprintf(SandAllocator *a, size_t *length_out, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + char *result = sand_vasprintf(a, length_out, fmt, ap); + va_end(ap); + return result; +} + +void sand_print_diagnostic(SandState *S, const SandLocation *location, SandDiagnosticLevel level, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + size_t message_length; + char *message = sand_vasprintf(&S->gpa, &message_length, fmt, ap); + va_end(ap); + + if (message == NULL) { + return; // FIXME: What do we do here? + } + + S->config.diagnostic_handler(location ,level, message, message_length); + sand_deallocate(&S->gpa, message, message_length + 1); } void sand_destroy_state(SandState *S) { diff --git a/src/core/state.h b/src/core/state.h index 85c604b..6f4d174 100644 --- a/src/core/state.h +++ b/src/core/state.h @@ -4,17 +4,22 @@ // This module defines the evaluator state. This is the "world" in Sand. // Multiple evaluator states can coexist as they are totally separate. +#include "utils.h" +#include "allocator.h" #include "config.h" -#include <stddef.h> - // This data structure should be treated as entirely opaque by consuming code. typedef struct { SandConfig config; + + SandAllocator gpa; } SandState; SandState sand_create_state(SandConfig config); +_SAND_FORMAT_ATTR(printf, 4, 5) +void sand_print_diagnostic(SandState *, const SandLocation *, SandDiagnosticLevel, const char *fmt, ...); + void sand_destroy_state(SandState *); #endif diff --git a/src/core/utils.h b/src/core/utils.h new file mode 100644 index 0000000..abb1665 --- /dev/null +++ b/src/core/utils.h @@ -0,0 +1,13 @@ +#ifndef SAND_COMPILER_ATTRIBUTES_H +#define SAND_COMPILER_ATTRIBUTES_H + +// This is a helper module which defines various small helpers. It should only +// be used internally, hence the underscore prefix. + +#ifdef __GNUC__ +#define _SAND_FORMAT_ATTR(archetype, string_index, first_to_check) __attribute__((format(archetype, string_index, first_to_check))) +#else +#define _SAND_FORMAT_ATTR(archetype, string_index, first_to_check) +#endif + +#endif |