aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-09-01 12:43:08 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-09-01 12:43:08 -0400
commit0a7062e2d711b5ac7fb71e873f293a8f0d0e8bc6 (patch)
tree912ae69dd9906dee11424433ff5367237296b0f6 /src
parent5fc7577b5a3bc2c445522dfd5b287e1c6eddc3e9 (diff)
Improved error messages
Diffstat (limited to 'src')
-rw-r--r--src/compile/expressions.c2
-rw-r--r--src/compile/indexing.c20
-rw-r--r--src/compile/indexing.h4
-rw-r--r--src/compile/optionals.c4
-rw-r--r--src/stdlib/lists.h10
-rw-r--r--src/stdlib/tables.h12
6 files changed, 46 insertions, 6 deletions
diff --git a/src/compile/expressions.c b/src/compile/expressions.c
index 2320474a..e21ee263 100644
--- a/src/compile/expressions.c
+++ b/src/compile/expressions.c
@@ -234,7 +234,7 @@ Text_t compile(env_t *env, ast_t *ast) {
case If: return compile_if_expression(env, ast);
case Reduction: return compile_reduction(env, ast);
case FieldAccess: return compile_field_access(env, ast);
- case Index: return compile_indexing(env, ast);
+ case Index: return compile_indexing(env, ast, false);
case InlineCCode: {
type_t *t = get_type(env, ast);
if (t->tag == VoidType) return Texts("{\n", compile_statement(env, ast), "\n}");
diff --git a/src/compile/indexing.c b/src/compile/indexing.c
index d2e98388..cca06184 100644
--- a/src/compile/indexing.c
+++ b/src/compile/indexing.c
@@ -1,5 +1,7 @@
// This file defines how to compile indexing like `list[i]` or `ptr[]`
+#include <stdbool.h>
+
#include "../ast.h"
#include "../config.h"
#include "../environment.h"
@@ -9,7 +11,7 @@
#include "compilation.h"
public
-Text_t compile_indexing(env_t *env, ast_t *ast) {
+Text_t compile_indexing(env_t *env, ast_t *ast, bool checked) {
DeclareMatch(indexing, ast, Index);
type_t *indexed_type = get_type(env, indexing->indexed);
if (!indexing->index) {
@@ -39,8 +41,14 @@ Text_t compile_indexing(env_t *env, ast_t *ast) {
? compile_int_to_type(env, indexing->index, Type(IntType, .bits = TYPE_IBITS64))
: (index_t->tag == BigIntType ? Texts("Int64$from_int(", compile(env, indexing->index), ", no)")
: Texts("(Int64_t)(", compile(env, indexing->index), ")"));
- return Texts("List_get(", list, ", ", index_code, ", ", compile_type(item_type), ", value, ",
- promote_to_optional(item_type, Text("value")), ", ", compile_none(item_type), ")");
+ if (checked) {
+ int64_t start = (int64_t)(ast->start - ast->file->text), end = (int64_t)(ast->end - ast->file->text);
+ return Texts("List_get_checked(", list, ", ", index_code, ", ", compile_type(item_type), ", ",
+ String(start), ", ", String(end), ")");
+ } else {
+ return Texts("List_get(", list, ", ", index_code, ", ", compile_type(item_type), ", value, ",
+ promote_to_optional(item_type, Text("value")), ", ", compile_none(item_type), ")");
+ }
} else if (container_t->tag == TableType) {
DeclareMatch(table_type, container_t, TableType);
if (table_type->default_value) {
@@ -49,6 +57,12 @@ Text_t compile_indexing(env_t *env, ast_t *ast) {
compile(env, indexing->index), ", ",
compile_to_type(env, table_type->default_value, table_type->value_type), ", ",
compile_type_info(container_t), ")");
+ } else if (checked) {
+ int64_t start = (int64_t)(ast->start - ast->file->text), end = (int64_t)(ast->end - ast->file->text);
+ return Texts("Table$get_checked(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
+ compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
+ compile(env, indexing->index), ", ", String(start), ", ", String(end), ", ",
+ compile_type_info(container_t), ")");
} else {
return Texts("Table$get_optional(", compile_to_pointer_depth(env, indexing->indexed, 0, false), ", ",
compile_type(table_type->key_type), ", ", compile_type(table_type->value_type), ", ",
diff --git a/src/compile/indexing.h b/src/compile/indexing.h
index bf30f98a..5b76692b 100644
--- a/src/compile/indexing.h
+++ b/src/compile/indexing.h
@@ -2,8 +2,10 @@
#pragma once
+#include <stdbool.h>
+
#include "../ast.h"
#include "../environment.h"
#include "../stdlib/datatypes.h"
-Text_t compile_indexing(env_t *env, ast_t *ast);
+Text_t compile_indexing(env_t *env, ast_t *ast, bool checked);
diff --git a/src/compile/optionals.c b/src/compile/optionals.c
index b3d94005..f32e925e 100644
--- a/src/compile/optionals.c
+++ b/src/compile/optionals.c
@@ -8,6 +8,7 @@
#include "../typecheck.h"
#include "../types.h"
#include "compilation.h"
+#include "indexing.h"
Text_t optional_into_nonnone(type_t *t, Text_t value) {
if (t->tag == OptionalType) t = Match(t, OptionalType)->type;
@@ -122,6 +123,7 @@ Text_t compile_optional(env_t *env, ast_t *ast) {
public
Text_t compile_non_optional(env_t *env, ast_t *ast) {
ast_t *value = Match(ast, NonOptional)->value;
+ if (value->tag == Index && Match(value, Index)->index != NULL) return compile_indexing(env, value, true);
type_t *t = get_type(env, value);
Text_t value_code = compile(env, value);
int64_t line = get_line_number(ast->file, ast->start);
@@ -129,6 +131,6 @@ Text_t compile_non_optional(env_t *env, ast_t *ast) {
check_none(t, Text("opt")), ")\n", "#line ", String(line), "\n", "fail_source(",
quoted_str(ast->file->filename), ", ", String((int64_t)(value->start - value->file->text)), ", ",
String((int64_t)(value->end - value->file->text)), ", ",
- "\"This was expected to be a value, but it's none\");\n", optional_into_nonnone(t, Text("opt")),
+ "\"This was expected to be a value, but it's `none`\\n\");\n", optional_into_nonnone(t, Text("opt")),
"; })");
}
diff --git a/src/stdlib/lists.h b/src/stdlib/lists.h
index 74314aa6..1386b2fa 100644
--- a/src/stdlib/lists.h
+++ b/src/stdlib/lists.h
@@ -10,6 +10,16 @@
#include "util.h"
// Convert negative indices to back-indexed without branching: index0 = index + (index < 0)*(len+1)) - 1
+#define List_get_checked(list_expr, index_expr, item_type, start, end) \
+ ({ \
+ const List_t list = list_expr; \
+ int64_t index = index_expr; \
+ int64_t off = index + (index < 0) * (list.length + 1) - 1; \
+ if (unlikely(off < 0 || off >= list.length)) \
+ fail_source(__SOURCE_FILE__, start, end, "Invalid list index: ", index, " (list has length ", \
+ (int64_t)list.length, ")\n"); \
+ *(item_type *)(list.data + list.stride * off); \
+ })
#define List_get(list_expr, index_expr, item_type, var, optional_expr, none_expr) \
({ \
const List_t list = list_expr; \
diff --git a/src/stdlib/tables.h b/src/stdlib/tables.h
index 208bf6b2..129aa5ec 100644
--- a/src/stdlib/tables.h
+++ b/src/stdlib/tables.h
@@ -49,6 +49,18 @@ void *Table$get(Table_t t, const void *key, const TypeInfo_t *type);
val_t *nonnull_var = Table$get(t, &k, info_expr); \
nonnull_var ? nonnull_expr : null_expr; \
})
+#define Table$get_checked(table_expr, key_t, val_t, key_expr, start, end, info_expr) \
+ ({ \
+ const Table_t t = table_expr; \
+ const key_t key = key_expr; \
+ const TypeInfo_t *info = info_expr; \
+ val_t *value = Table$get(t, &key, info); \
+ if (unlikely(value == NULL)) \
+ fail_source(__SOURCE_FILE__, start, end, \
+ "This key was not found in the table: ", generic_as_text(&key, false, info->TableInfo.key), \
+ "\n"); \
+ *value; \
+ })
#define Table$get_or_setdefault(table_expr, key_t, val_t, key_expr, default_expr, info_expr) \
({ \
Table_t *t = table_expr; \