1 Commits

Author SHA1 Message Date
d715bc0625 Report prescan errors on their source lines
Some checks failed
akbasic CI Build / coverage (push) Failing after 27s
akbasic CI Build / cmake_build (push) Failing after 33s
akbasic CI Build / akgl_build (push) Failing after 18s
akbasic CI Build / sanitizers (push) Failing after 1m7s
akbasic CI Build / mutation_test (push) Failing after 39s
2026-08-05 06:40:14 -04:00
8 changed files with 98 additions and 4 deletions

View File

@@ -50,7 +50,7 @@ nothing would say which type it is.
```
```output
? 40 : PARSE ERROR TYPE POINT: POINT is a reserved word and cannot name a type
? 10 : PARSE ERROR TYPE POINT: POINT is a reserved word and cannot name a type
```

View File

@@ -160,14 +160,21 @@ akerr_ErrorContext *akbasic_data_scan(akbasic_Runtime *obj)
{
PREPARE_ERROR(errctx);
int64_t i = 0;
int64_t entry = 0;
FAIL_ZERO_RETURN(errctx, (obj != NULL), AKERR_NULLPOINTER, "NULL runtime in data_scan");
FAIL_ZERO_RETURN(errctx, (obj->environment != NULL), AKERR_NULLPOINTER,
"Runtime has no environment; call akbasic_runtime_init() first");
entry = obj->environment->lineno;
PASS(errctx, akbasic_data_state_init(&obj->data_state));
for ( i = 0; i < AKBASIC_MAX_SOURCE_LINES; i++ ) {
if ( obj->source[i].code[0] != '\0' ) {
/* Keep BASIC's error prefix on the source line being prescanned. */
obj->environment->lineno = i;
PASS(errctx, scan_line(&obj->data_state, obj->source[i].code, i));
}
}
obj->environment->lineno = entry;
SUCCEED_RETURN(errctx);
}

View File

@@ -1576,17 +1576,22 @@ akerr_ErrorContext *akbasic_runtime_scan_labels(akbasic_Runtime *obj)
PREPARE_ERROR(errctx);
akbasic_Environment *root = NULL;
int64_t i = 0;
int64_t entry = 0;
FAIL_ZERO_RETURN(errctx, (obj != NULL), AKERR_NULLPOINTER, "NULL runtime in scan_labels");
FAIL_ZERO_RETURN(errctx, (obj->environment != NULL), AKERR_NULLPOINTER,
"Runtime has no environment; call akbasic_runtime_init() first");
for ( root = obj->environment; root->parent != NULL; root = root->parent ) {
}
entry = obj->environment->lineno;
for ( i = 0; i < AKBASIC_MAX_SOURCE_LINES; i++ ) {
if ( obj->source[i].code[0] != '\0' ) {
/* Keep BASIC's error prefix on the source line being prescanned. */
obj->environment->lineno = i;
PASS(errctx, scan_line_labels(root, obj->source[i].code, i));
}
}
obj->environment->lineno = entry;
SUCCEED_RETURN(errctx);
}

View File

@@ -260,11 +260,13 @@ static akerr_ErrorContext *scan_names(akbasic_Runtime *obj)
size_t namelen = 0;
bool matched = false;
const akbasic_Verb *verb = NULL;
int64_t entry = obj->environment->lineno;
for ( i = 0; i < AKBASIC_MAX_SOURCE_LINES; i++ ) {
if ( obj->source[i].code[0] == '\0' ) {
continue;
}
obj->environment->lineno = i;
cursor = next_word(skip_lineno(obj->source[i].code), word, sizeof(word));
PASS(errctx, word_is(word, "END", &matched));
@@ -327,6 +329,7 @@ static akerr_ErrorContext *scan_names(akbasic_Runtime *obj)
FAIL_NONZERO_RETURN(errctx, (open >= 0), AKBASIC_ERR_SYNTAX,
"TYPE %s is never closed with END TYPE", table->types[open >= 0 ? open : 0].name);
obj->environment->lineno = entry;
SUCCEED_RETURN(errctx);
}
@@ -440,7 +443,7 @@ static akerr_ErrorContext *parse_field(akbasic_StructTypeTable *table, akbasic_S
* each other by value, which has no finite size. That is the diagnosis rather
* than a stack overflow later.
*/
static akerr_ErrorContext *resolve_sizes(akbasic_StructTypeTable *table)
static akerr_ErrorContext *resolve_sizes(akbasic_Runtime *runtime, akbasic_StructTypeTable *table)
{
PREPARE_ERROR(errctx);
bool progress = true;
@@ -477,6 +480,7 @@ static akerr_ErrorContext *resolve_sizes(akbasic_StructTypeTable *table)
}
for ( i = 0; i < table->count; i++ ) {
runtime->environment->lineno = table->types[i].firstline;
FAIL_NONZERO_RETURN(errctx, (table->types[i].slotcount < 0), AKBASIC_ERR_VALUE,
"TYPE %s contains itself by value, so it has no size. "
"A type may only refer to itself through PTR TO",
@@ -493,9 +497,13 @@ akerr_ErrorContext *akbasic_structtype_scan(akbasic_Runtime *obj)
akbasic_StructTypeTable *table = NULL;
int64_t i = 0;
int t = 0;
int64_t entry = 0;
FAIL_ZERO_RETURN(errctx, (obj != NULL), AKERR_NULLPOINTER, "NULL runtime in structtype scan");
FAIL_ZERO_RETURN(errctx, (obj->environment != NULL), AKERR_NULLPOINTER,
"Runtime has no environment; call akbasic_runtime_init() first");
table = &obj->structtypes;
entry = obj->environment->lineno;
/*
* Drop what the *script* declared and keep what the *host* registered.