refactor-error-handling #12

Merged
laentropia merged 11 commits from refactor-error-handling into main 2026-05-13 19:05:55 -06:00
5 changed files with 111 additions and 20 deletions
Showing only changes of commit efa0e3bacd - Show all commits

View File

@@ -5,7 +5,22 @@
#include "parser.h" #include "parser.h"
#include <stdint.h> #include <stdint.h>
int64_t evaluate(ParseResult context); typedef enum {
int64_t evaluate_tree(ASTNode *tree); EVALUATOR_OK,
EVALUATOR_MATH_ERR,
EVALUATOR_INVALID_PARSING,
EVALUATOR_INVALID_TREE, // just to shut up the compiler with the swithces
} EvaluatorErr;
typedef struct {
bool is_valid;
union {
int64_t val;
EvaluatorErr err;
};
} EvaluatorResult;
EvaluatorResult evaluate(ParserResult context);
EvaluatorResult evaluate_tree(Node *tree);
#endif // !EVALUATOR_H #endif // !EVALUATOR_H

View File

@@ -37,6 +37,7 @@ typedef enum {
PARSER_MISSING_OPERAND, PARSER_MISSING_OPERAND,
PARSER_UNMATCHED_PAREN, PARSER_UNMATCHED_PAREN,
PARSER_OUT_OF_MEMORY, PARSER_OUT_OF_MEMORY,
PARSER_INVALID_TOKENIZE,
} ParserErr; } ParserErr;
typedef struct { typedef struct {

View File

@@ -2,36 +2,97 @@
#include "arena.h" #include "arena.h"
#include "lexer.h" #include "lexer.h"
#include "parser.h" #include "parser.h"
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <math.h> #include <math.h>
int64_t evaluate_tree(ASTNode *tree) { EvaluatorResult evaluate_tree(Node *tree) {
if (tree->type == NODE_BINARY_OP) { if (tree->type == NODE_BINARY_OP) {
Operator op = tree->data.binary.op; Operator op = tree->binary.op;
ASTNode *left = tree->data.binary.left; Node *left = tree->binary.left;
ASTNode *right = tree->data.binary.right; Node *right = tree->binary.right;
switch (op) { switch (op) {
case OP_ADD: case OP_ADD: {
return evaluate_tree(left) + evaluate_tree(right); EvaluatorResult left_result = evaluate_tree(left);
case OP_SUB: EvaluatorResult right_result = evaluate_tree(right);
return evaluate_tree(left) - evaluate_tree(right); if (!left_result.is_valid || !right_result.is_valid) {
case OP_MUL: return left_result;
return evaluate_tree(left) * evaluate_tree(right);
case OP_DIV:
return evaluate_tree(left) / evaluate_tree(right);
case OP_POW:
return pow(evaluate_tree(left), evaluate_tree(right));
} }
return (EvaluatorResult) {
.is_valid = true,
.val = left_result.val + right_result.val,
};
}
case OP_SUB: {
EvaluatorResult left_result = evaluate_tree(left);
EvaluatorResult right_result = evaluate_tree(right);
if (!left_result.is_valid || !right_result.is_valid) {
return left_result;
}
return (EvaluatorResult) {
.is_valid = true,
.val = left_result.val - right_result.val,
};
}
case OP_MUL: {
EvaluatorResult left_result = evaluate_tree(left);
EvaluatorResult right_result = evaluate_tree(right);
if (!left_result.is_valid || !right_result.is_valid) {
return left_result;
}
return (EvaluatorResult) {
.is_valid = true,
.val = left_result.val * right_result.val,
};
}
case OP_DIV: {
EvaluatorResult left_result = evaluate_tree(left);
EvaluatorResult right_result = evaluate_tree(right);
if (!left_result.is_valid || !right_result.is_valid) {
return left_result;
}
return (EvaluatorResult) {
.is_valid = true,
.val = left_result.val / right_result.val,
};
}
case OP_POW: {
EvaluatorResult left_result = evaluate_tree(left);
EvaluatorResult right_result = evaluate_tree(right);
if (!left_result.is_valid || !right_result.is_valid) {
return left_result;
}
return (EvaluatorResult) {
.is_valid = true,
.val = pow(left_result.val, right_result.val),
};
}
default:
return (EvaluatorResult) {
.is_valid = false,
.err = EVALUATOR_INVALID_TREE,
};
}
} else if (tree->type == NODE_UNARY_OP) {
} }
int64_t return_val = tree->data.integer; int64_t return_val = tree->data.integer;
return return_val; return return_val;
} }
int64_t evaluate(ParseResult context) { EvaluatorResult evaluate(ParseResult context) {
int64_t result = evaluate_tree(context.tree); if (!context.is_valid) {
return (EvaluatorResult) {
.is_valid = false,
.err = EVALUATOR_INVALID_PARSING,
};
}
EvaluatorResult result = evaluate_tree(context.tree);
arena_destroy(&context.arena); arena_destroy(&context.arena);
return result; return result;

View File

@@ -27,6 +27,7 @@ TokenizeResult tokenize(const char *input) {
TokenResult result = tokenize_number(input, &offset); TokenResult result = tokenize_number(input, &offset);
if (!result.is_valid) { if (!result.is_valid) {
arraylist_destroy(&arr);
return (TokenizeResult) {.is_valid = false, .err = result.err}; return (TokenizeResult) {.is_valid = false, .err = result.err};
} }
@@ -41,6 +42,7 @@ TokenizeResult tokenize(const char *input) {
} else if (isspace(input[offset])) { } else if (isspace(input[offset])) {
// Nothing... // Nothing...
} else { } else {
arraylist_destroy(&arr);
return (TokenizeResult) { return (TokenizeResult) {
.is_valid = false, .is_valid = false,
.err = LEXER_NOT_RECOGNIZED_SYMBOL}; .err = LEXER_NOT_RECOGNIZED_SYMBOL};
@@ -50,6 +52,7 @@ TokenizeResult tokenize(const char *input) {
} }
if (arraylist_size(arr) < 1) { if (arraylist_size(arr) < 1) {
arraylist_destroy(&arr);
return (TokenizeResult) {.is_valid = false, .err = LEXER_EMPTY_INPUT}; return (TokenizeResult) {.is_valid = false, .err = LEXER_EMPTY_INPUT};
} }

View File

@@ -120,6 +120,8 @@ ParserU8Result infix_rbp(Node node) {
} }
} }
Node token_to_node(Token token) { Node token_to_node(Token token) {
if (token.type == TOKEN_INTEGER) { if (token.type == TOKEN_INTEGER) {
return (Node) { return (Node) {
@@ -151,7 +153,7 @@ Node token_to_node(Token token) {
}; };
case OP_POW: case OP_POW:
return (Node) { return (Node) {
.type = NODE_UNARY_OP, .type = NODE_BINARY_OP,
.binary.op = token.op, .binary.op = token.op,
}; };
case OP_FACTORIAL: case OP_FACTORIAL:
@@ -173,17 +175,27 @@ Node token_to_node(Token token) {
} }
ParserResult parse(TokenizeResult tokens) { ParserResult parse(TokenizeResult tokens) {
if (!tokens.is_valid) {
return (ParserResult) {
.is_valid = false,
.err = PARSER_INVALID_TOKENIZE,
};
}
ArraySlice *context = arraylist_slice(tokens.arr, 0, arraylist_size(tokens.arr)); ArraySlice *context = arraylist_slice(tokens.arr, 0, arraylist_size(tokens.arr));
Arena arena = arena_init(sizeof(Node) * arraylist_size(tokens.arr)).arena; Arena arena = arena_init(sizeof(Node) * arraylist_size(tokens.arr)).arena;
NodeResult result = parse_expr(context, &arena, 0); NodeResult result = parse_expr(context, &arena, 0);
if (!result.is_valid) { if (!result.is_valid) {
arena_destroy(&arena);
arraylist_destroy(&tokens.arr);
return (ParserResult) { return (ParserResult) {
.is_valid = false, .is_valid = false,
.err = result.err, .err = result.err,
}; };
} }
arraylist_destroy(&tokens.arr);
return (ParserResult) { return (ParserResult) {
.is_valid = true, .is_valid = true,
.arena = arena, .arena = arena,
@@ -352,7 +364,6 @@ NodeResult parse_expr(ArraySlice *slice, Arena *arena, uint8_t min_bp) {
break; break;
} }
// Final: return left side // Final: return left side
return (NodeResult){ return (NodeResult){
.is_valid = true, .is_valid = true,