Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 0 additions & 31 deletions include/snuk/interpreter/error_code.h

This file was deleted.

12 changes: 11 additions & 1 deletion include/snuk/interpreter/interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "snuk/parser/snuk_expr.h"
#include "snuk/parser/snuk_item.h"
#include "snuk/refcount.h"
#include "snuk/snuk_error.h"
#include "snuk/string_view.h"
#include "snuk_env.h"
#include "snuk_signal.h"
Expand All @@ -19,6 +20,9 @@
* and for loops push and pop scopes. global is retained for the lifetime of
* the interpreter so identifiers can fall through to the root. signal carries
* the most recent control-flow signal raised during evaluation.
*
* err holds the first error encountered during item execution. The consumer
* reads it via snuk_interpreter_clear_error() after each exec_item call.
*/
typedef struct SnukInterpreter {
SnukRefCounter *current;
Expand All @@ -29,7 +33,9 @@ typedef struct SnukInterpreter {
void *mem;
SnukAllocator allocator;
snLinearAllocator la;
SnukErrorCode err_code;
SnukError err;
SnukSrcLoc cur_loc;
char err_msg_buf[256];
} SnukInterpreter;

/**
Expand Down Expand Up @@ -90,3 +96,7 @@ SNUK_API bool snuk_interpreter_create_env(
SnukInterpreter *intpret, SnukStringView name, SnukType *type, SnukValue value, bool is_const);

SNUK_API bool snuk_interpreter_value_is_of_type(SnukInterpreter *intpret, SnukValue value, SnukType *type);

SNUK_API SnukError snuk_interpreter_clear_error(SnukInterpreter *intpret);

SNUK_API void snuk_interpreter_set_loc(SnukInterpreter *intpret, uint32_t line, uint32_t col);
35 changes: 31 additions & 4 deletions include/snuk/interpreter/interpreter_helper.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,46 @@
#pragma once

#include "error_code.h"
#include "interpreter.h"
#include "snuk/darray.h"
#include "snuk/defines.h"
#include "snuk/snuk_error.h"
#include "snuk_scope.h"

#include <stdarg.h>
#include <stdio.h>

SnukValue execute_block_expr(
SnukInterpreter *intpret, SnukExpr *block, int capture_signals, int propogate_signals, bool weak_ref);

SnukValue interpreter_copy_inst(SnukInterpreter *intpret, SnukValue inst);

SNUK_INLINE void interpreter_error(SnukInterpreter *intpret, SnukErrorCode err_code) {
if (intpret->err_code != SNUK_ERROR_NONE) return;
intpret->err_code = err_code;
SNUK_INLINE void interpreter_error(SnukInterpreter *intpret, SnukInterpError code, const char *msg) {
if (intpret->err.kind != SNUK_ERROR_KIND_NONE) return;
intpret->err = (SnukError){
.kind = SNUK_ERROR_KIND_INTERP,
.code = (uint32_t)code,
.msg = msg,
.loc = intpret->cur_loc,
};
}

SNUK_INLINE void interpreter_error_fmt(SnukInterpreter *intpret, SnukInterpError code, const char *fmt, ...) {
if (intpret->err.kind != SNUK_ERROR_KIND_NONE) return;
va_list args;
va_start(args, fmt);
vsnprintf(intpret->err_msg_buf, sizeof(intpret->err_msg_buf), fmt, args);
va_end(args);
intpret->err = (SnukError){
.kind = SNUK_ERROR_KIND_INTERP,
.code = (uint32_t)code,
.msg = intpret->err_msg_buf,
.loc = intpret->cur_loc,
};
}

SNUK_INLINE void interpreter_set_loc(SnukInterpreter *intpret, uint32_t line, uint32_t col) {
intpret->cur_loc.line = line;
intpret->cur_loc.col = col;
}

/**
Expand Down
2 changes: 0 additions & 2 deletions include/snuk/interpreter/snuk_value.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#pragma once

#include "error_code.h"
#include "snuk/defines.h"
#include "snuk/parser/snuk_expr.h"
#include "snuk/parser/snuk_type.h"
Expand Down Expand Up @@ -43,7 +42,6 @@ typedef enum SnukValueType {
*/
struct SnukValue {
SnukValueType type;
SnukErrorCode err_code;

union {
int64_t int_value;
Expand Down
18 changes: 14 additions & 4 deletions include/snuk/parser/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "snuk/defines.h"
#include "snuk/lexer.h"
#include "snuk/snuk_error.h"

/*
* We will have items similar to rust.
Expand Down Expand Up @@ -32,8 +33,7 @@ typedef struct SnukParser {
SnukAllocator *allocator;

bool panic_mode; /**< Error and recovery state flags. */
const char *err_msg;
SnukToken err_token;
SnukError err;
} SnukParser;

/**
Expand Down Expand Up @@ -74,9 +74,19 @@ SNUK_API SnukItem *snuk_parser_next_item(SnukParser *parser);
* @brief Report a parser error and enter panic mode.
*
* @param parser Parser context to operate on.
* @param err_msg Error message to print.
* @param code Parse error code.
* @param msg Error message to print.
*/
void parser_error(SnukParser *parser, const char *err_msg);
void parser_error(SnukParser *parser, SnukParseError code, const char *msg);

/**
* @brief Clear the parser error state.
*
* @param parser Parser context to operate on.
*
* @return Previous error value.
*/
SnukError snuk_parser_clear_error(SnukParser *parser);

/**
* @brief Recover parser state after an error.
Expand Down
14 changes: 10 additions & 4 deletions include/snuk/parser/parser_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ typedef struct SnukVar SnukVar;
SNUK_INLINE void parser_advance(SnukParser *parser) {
parser->previous = parser->current;
parser->current = parser->next;
if (parser->current.type == SNUK_TOKEN_ERROR) parser_error(parser, "lexer error");
if (parser->current.type == SNUK_TOKEN_ERROR)
parser_error(parser, SNUK_PARSE_ERR_LEXER_ERROR, "lexer error");
parser->next = snuk_lexer_next_token(&parser->lexer);
}

Expand Down Expand Up @@ -68,8 +69,12 @@ SNUK_INLINE bool parser_match(SnukParser *parser, SnukTokenType expected) {
* @param expected Expected token type.
* @param err_msg Error message to report if the token does not match.
*/
SNUK_INLINE void parser_expect(SnukParser *parser, SnukTokenType expected, const char *err_msg) {
if (!parser_match(parser, expected)) parser_error(parser, err_msg);
SNUK_INLINE bool parser_expect(SnukParser *parser, SnukTokenType expected, const char *err_msg) {
if (!parser_match(parser, expected)) {
parser_error(parser, SNUK_PARSE_ERR_UNEXPECTED_TOKEN, err_msg);
return false;
}
return true;
}

SNUK_INLINE bool parser_check_item_end(SnukParser *parser) {
Expand Down Expand Up @@ -97,7 +102,8 @@ SNUK_INLINE bool parser_match_item_end(SnukParser *parser) {
* @param parser Parser context to operate on.
*/
SNUK_INLINE void parser_expect_item_end(SnukParser *parser) {
if (!parser_match_item_end(parser)) parser_error(parser, "expected a new line or a semicolon");
if (!parser_match_item_end(parser))
parser_error(parser, SNUK_PARSE_ERR_EXPECTED_SEMICOLON_OR_NEWLINE, "expected a new line or a semicolon");
}

SNUK_INLINE SnukStringView parser_copy_string_view(SnukParser *parser, SnukStringView sv) {
Expand Down
12 changes: 5 additions & 7 deletions include/snuk/parser/snuk_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "parser_common.h"
#include "snuk/darray.h"
#include "snuk/defines.h"
#include "snuk/snuk_error.h"
#include "snuk/string_view.h"
#include "snuk_type.h"

Expand Down Expand Up @@ -57,8 +58,7 @@ struct SnukItem {
} interface_item;

struct {
const char *msg;
SnukToken token;
SnukError error;
} error;
};
};
Expand Down Expand Up @@ -215,18 +215,16 @@ SNUK_INLINE SnukItem *build_interface_item(SnukParser *parser, SnukStringView na
* @brief Build a error item.
*
* @param parser Parser context to operate on.
* @param msg The message
* @param token The token
* @param error The error
*
* @return Return error item.
*/
SNUK_INLINE SnukItem *build_error_item(SnukParser *parser, const char *msg, SnukToken token) {
SNUK_INLINE SnukItem *build_error_item(SnukParser *parser, SnukError error) {
SnukItem *item = parser_create_item(parser);
*item = (SnukItem){
.type = SNUK_ITEM_ERROR,
.error = {
.msg = msg,
.token = token,
.error = error,
},
};
return item;
Expand Down
78 changes: 78 additions & 0 deletions include/snuk/snuk_error.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

#include <stdint.h>

typedef struct {
const char *file; // filename or NULL
uint32_t line; // 1-indexed
uint32_t col; // 1-indexed
} SnukSrcLoc;

#define SNUK_SRC_LOC_NULL ((SnukSrcLoc){NULL, 0, 0})

typedef enum {
SNUK_ERROR_KIND_NONE = 0,
SNUK_ERROR_KIND_PARSE,
SNUK_ERROR_KIND_INTERP,
} SnukErrorKind;

typedef enum {
SNUK_INTERP_ERR_NONE = 0,
SNUK_INTERP_ERR_TYPE, // type system violations
SNUK_INTERP_ERR_NAME, // name resolution / declaration conflicts
SNUK_INTERP_ERR_FUNCALL, // function call errors
SNUK_INTERP_ERR_ASSIGN, // assignment / initialization failures
SNUK_INTERP_ERR_CONTROL_FLOW, // break/continue/return outside valid scope
SNUK_INTERP_ERR_INTERFACE, // interface creation errors
SNUK_INTERP_ERR_INTERNAL, // unexpected/unreachable code paths
} SnukInterpError;

typedef enum {
SNUK_PARSE_ERR_NONE = 0,
SNUK_PARSE_ERR_UNEXPECTED_TOKEN,
SNUK_PARSE_ERR_EXPECTED_IDENTIFIER,
SNUK_PARSE_ERR_EXPECTED_TYPE_ANNOTATION,
SNUK_PARSE_ERR_EXPECTED_SEMICOLON_OR_NEWLINE,
SNUK_PARSE_ERR_EXPECTED_CLOSE_BRACE,
SNUK_PARSE_ERR_EXPECTED_CLOSE_PAREN,
SNUK_PARSE_ERR_EXPECTED_CLOSE_BRACKET,
SNUK_PARSE_ERR_EXPECTED_KEYWORD,
SNUK_PARSE_ERR_EXPECTED_EXPRESSION,
SNUK_PARSE_ERR_EXPECTED_TYPE,
SNUK_PARSE_ERR_EXPECTED_MEMBER,
SNUK_PARSE_ERR_INVALID_LITERAL,
SNUK_PARSE_ERR_UNTERMINATED_STRING,
SNUK_PARSE_ERR_LEXER_ERROR,
SNUK_PARSE_ERR_UNKNOWN,
} SnukParseError;

typedef struct {
SnukErrorKind kind;
uint32_t code; // cast from SnukInterpError or SnukParseError
const char *msg; // human-readable description
SnukSrcLoc loc;
} SnukError;

#define SNUK_ERROR_NONE ((SnukError){SNUK_ERROR_KIND_NONE, 0, NULL, SNUK_SRC_LOC_NULL})

static inline const char *snuk_interp_error_msg(SnukInterpError code) {
switch (code) {
case SNUK_INTERP_ERR_NONE:
return "no error";
case SNUK_INTERP_ERR_TYPE:
return "type error";
case SNUK_INTERP_ERR_NAME:
return "name error";
case SNUK_INTERP_ERR_FUNCALL:
return "function call error";
case SNUK_INTERP_ERR_ASSIGN:
return "assignment error";
case SNUK_INTERP_ERR_CONTROL_FLOW:
return "control flow error";
case SNUK_INTERP_ERR_INTERFACE:
return "interface error";
case SNUK_INTERP_ERR_INTERNAL:
return "internal error";
}
return "unknown error";
}
19 changes: 14 additions & 5 deletions repl/runtime.c
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#include "runtime.h"

#include <snuk/interpreter/error_code.h>
#include <snuk/logger.h>
#include <snuk/parser/parser.h>
#include <snuk/snuk_error.h>

void snuk_runtime_execute(Runtime *rt, const char *src) {
SnukParser parser;
Expand All @@ -12,11 +12,20 @@ void snuk_runtime_execute(Runtime *rt, const char *src) {
while (true) {
item = snuk_parser_next_item(&parser);
if (!item) break;
// snuk_item_log(item);
// log_trace("", NULL);

SnukError parse_err = snuk_parser_clear_error(&parser);
if (parse_err.kind != SNUK_ERROR_KIND_NONE) {
log_error("[Error] at line %u, col %u: %s", parse_err.loc.line, parse_err.loc.col,
parse_err.msg);
continue;
}

SnukValue value = snuk_interpreter_exec_item(&rt->interpreter, item);
if (value.err_code) {
log_error("%s", snuk_error_code_get_msg(value.err_code));
SnukError err = snuk_interpreter_clear_error(&rt->interpreter);
if (err.kind != SNUK_ERROR_KIND_NONE) {
if (err.loc.line)
log_error("[Error] at line %u, col %u: %s", err.loc.line, err.loc.col, err.msg);
else log_error("[Error] %s", err.msg);
}
snuk_value_log(value);
log_trace("", NULL);
Expand Down
2 changes: 0 additions & 2 deletions src/interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ set(PUBLIC_HEADERS
snuk_scope.h
snuk_env.h
native.h
error_code.h
)

set(HEADERS
Expand All @@ -14,7 +13,6 @@ set(HEADERS
set(SRCS
interpreter.c
snuk_value.c
error_code.c
native.c
)

Expand Down
Loading
Loading