fix(selfhost/parser): skip newlines inside expressions
The selfhost parser did not skip tkNewLine tokens inside expression parsing,
causing multi-line expressions (e.g. if conditions spanning lines with ||)
to be truncated. When parserParseBinaryPrec hit a newline it treated it as
an invalid primary, returning a malformed literal and leaving p.pos at the
newline. parserParseBlock then failed to find '{' and its depth-counter
fallback consumed far too many tokens, causing subsequent function bodies
to be parsed into the wrong AST nodes.
Fix: add newline skipping in parserParsePrimary, parserParseUnary, and
parserParseBinaryPrec, matching the bootstrap parser's skipNewlines() calls
in parseAnd/parseOr.
Also complete the variant cap raise from 8->9 in src/sema.bux (was already
done in ast.bux, parser.bux, hir_lower.bux).
This commit is contained in:
+50
-20
@@ -647,45 +647,75 @@ unsigned int bux_hash_string(const char* s) {
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
/* bux_list_dir: returns array of file paths in dir matching ext suffix.
|
/* bux_list_dir: returns array of file paths in dir (recursively) matching ext suffix.
|
||||||
* Result is malloc'd array of malloc'd strings. Caller must free.
|
* Result is malloc'd array of malloc'd strings. Caller must free.
|
||||||
* Sets *out_count to number of files found. */
|
* Sets *out_count to number of files found. */
|
||||||
char** bux_list_dir(const char* dir, const char* ext, int* out_count) {
|
static int bux_count_files_recursive(const char* dir, const char* ext, size_t ext_len) {
|
||||||
DIR* d = opendir(dir);
|
DIR* d = opendir(dir);
|
||||||
if (!d) { *out_count = 0; return NULL; }
|
if (!d) return 0;
|
||||||
|
|
||||||
/* First pass: count matching files */
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
size_t ext_len = strlen(ext);
|
|
||||||
struct dirent* entry;
|
struct dirent* entry;
|
||||||
while ((entry = readdir(d)) != NULL) {
|
while ((entry = readdir(d)) != NULL) {
|
||||||
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
||||||
|
size_t path_len = strlen(dir) + 1 + strlen(entry->d_name) + 1;
|
||||||
|
char* path = (char*)malloc(path_len);
|
||||||
|
if (!path) continue;
|
||||||
|
snprintf(path, path_len, "%s/%s", dir, entry->d_name);
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
count += bux_count_files_recursive(path, ext, ext_len);
|
||||||
|
} else {
|
||||||
size_t name_len = strlen(entry->d_name);
|
size_t name_len = strlen(entry->d_name);
|
||||||
if (name_len > ext_len && strcmp(entry->d_name + name_len - ext_len, ext) == 0) {
|
if (name_len > ext_len && strcmp(entry->d_name + name_len - ext_len, ext) == 0) {
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
closedir(d);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate result array */
|
static int bux_collect_files_recursive(const char* dir, const char* ext, size_t ext_len, char** result, int idx) {
|
||||||
char** result = (char**)malloc(count * sizeof(char*));
|
DIR* d = opendir(dir);
|
||||||
if (!result) { closedir(d); *out_count = 0; return NULL; }
|
if (!d) return idx;
|
||||||
|
struct dirent* entry;
|
||||||
/* Second pass: collect paths */
|
while ((entry = readdir(d)) != NULL) {
|
||||||
rewinddir(d);
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue;
|
||||||
int idx = 0;
|
size_t path_len = strlen(dir) + 1 + strlen(entry->d_name) + 1;
|
||||||
size_t dir_len = strlen(dir);
|
char* path = (char*)malloc(path_len);
|
||||||
while ((entry = readdir(d)) != NULL && idx < count) {
|
if (!path) continue;
|
||||||
|
snprintf(path, path_len, "%s/%s", dir, entry->d_name);
|
||||||
|
struct stat st;
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
idx = bux_collect_files_recursive(path, ext, ext_len, result, idx);
|
||||||
|
free(path);
|
||||||
|
} else {
|
||||||
size_t name_len = strlen(entry->d_name);
|
size_t name_len = strlen(entry->d_name);
|
||||||
if (name_len > ext_len && strcmp(entry->d_name + name_len - ext_len, ext) == 0) {
|
if (name_len > ext_len && strcmp(entry->d_name + name_len - ext_len, ext) == 0) {
|
||||||
/* Build full path: dir/name */
|
|
||||||
size_t path_len = dir_len + 1 + name_len + 1;
|
|
||||||
char* path = (char*)malloc(path_len);
|
|
||||||
if (path) {
|
|
||||||
snprintf(path, path_len, "%s/%s", dir, entry->d_name);
|
|
||||||
result[idx++] = path;
|
result[idx++] = path;
|
||||||
|
} else {
|
||||||
|
free(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
char** bux_list_dir(const char* dir, const char* ext, int* out_count) {
|
||||||
|
size_t ext_len = strlen(ext);
|
||||||
|
int count = bux_count_files_recursive(dir, ext, ext_len);
|
||||||
|
if (count == 0) { *out_count = 0; return NULL; }
|
||||||
|
char** result = (char**)malloc(count * sizeof(char*));
|
||||||
|
if (!result) { *out_count = 0; return NULL; }
|
||||||
|
int idx = bux_collect_files_recursive(dir, ext, ext_len, result, 0);
|
||||||
*out_count = idx;
|
*out_count = idx;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ struct Decl {
|
|||||||
variant5: EnumVariant,
|
variant5: EnumVariant,
|
||||||
variant6: EnumVariant,
|
variant6: EnumVariant,
|
||||||
variant7: EnumVariant,
|
variant7: EnumVariant,
|
||||||
|
variant8: EnumVariant,
|
||||||
// Impl methods (up to 4)
|
// Impl methods (up to 4)
|
||||||
methodCount: int,
|
methodCount: int,
|
||||||
// Use/import
|
// Use/import
|
||||||
|
|||||||
@@ -1006,6 +1006,7 @@ func HirLower_LowerModule(mod: *Module, sema: *Sema) -> *HirModule {
|
|||||||
if vi == 5 { v = &decl.variant5; }
|
if vi == 5 { v = &decl.variant5; }
|
||||||
if vi == 6 { v = &decl.variant6; }
|
if vi == 6 { v = &decl.variant6; }
|
||||||
if vi == 7 { v = &decl.variant7; }
|
if vi == 7 { v = &decl.variant7; }
|
||||||
|
if vi == 8 { v = &decl.variant8; }
|
||||||
if v != null as *EnumVariant {
|
if v != null as *EnumVariant {
|
||||||
hm.enums[ei].variants[vi].name = v.name;
|
hm.enums[ei].variants[vi].name = v.name;
|
||||||
hm.enums[ei].variants[vi].fieldCount = v.fieldCount;
|
hm.enums[ei].variants[vi].fieldCount = v.fieldCount;
|
||||||
|
|||||||
+11
-1
@@ -236,6 +236,9 @@ func parserMakeExpr(kind: int, line: uint32, col: uint32) -> *Expr {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
func parserParsePrimary(p: *Parser) -> *Expr {
|
func parserParsePrimary(p: *Parser) -> *Expr {
|
||||||
|
while parserCheck(p, tkNewLine) {
|
||||||
|
discard parserAdvance(p);
|
||||||
|
}
|
||||||
let tok: LexToken = parserCurToken(p);
|
let tok: LexToken = parserCurToken(p);
|
||||||
let line: uint32 = tok.line;
|
let line: uint32 = tok.line;
|
||||||
let col: uint32 = tok.column;
|
let col: uint32 = tok.column;
|
||||||
@@ -572,6 +575,9 @@ func parserPrecedence(op: int) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func parserParseUnary(p: *Parser) -> *Expr {
|
func parserParseUnary(p: *Parser) -> *Expr {
|
||||||
|
while parserCheck(p, tkNewLine) {
|
||||||
|
discard parserAdvance(p);
|
||||||
|
}
|
||||||
let tok: LexToken = parserCurToken(p);
|
let tok: LexToken = parserCurToken(p);
|
||||||
let line: uint32 = tok.line;
|
let line: uint32 = tok.line;
|
||||||
let col: uint32 = tok.column;
|
let col: uint32 = tok.column;
|
||||||
@@ -592,6 +598,9 @@ func parserParseUnary(p: *Parser) -> *Expr {
|
|||||||
func parserParseBinaryPrec(p: *Parser, minPrec: int) -> *Expr {
|
func parserParseBinaryPrec(p: *Parser, minPrec: int) -> *Expr {
|
||||||
var left: *Expr = parserParseUnary(p);
|
var left: *Expr = parserParseUnary(p);
|
||||||
while true {
|
while true {
|
||||||
|
while parserCheck(p, tkNewLine) {
|
||||||
|
discard parserAdvance(p);
|
||||||
|
}
|
||||||
let op: int = parserPeek(p, 0);
|
let op: int = parserPeek(p, 0);
|
||||||
let prec: int = parserPrecedence(op);
|
let prec: int = parserPrecedence(op);
|
||||||
if prec < minPrec { break; }
|
if prec < minPrec { break; }
|
||||||
@@ -1851,7 +1860,7 @@ func parserParseEnumDecl(p: *Parser, isPublic: bool) -> *Decl {
|
|||||||
|
|
||||||
discard parserExpect(p, tkLBrace, "expected '{'");
|
discard parserExpect(p, tkLBrace, "expected '{'");
|
||||||
while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile {
|
while !parserCheck(p, tkRBrace) && parserPeek(p, 0) != tkEndOfFile {
|
||||||
if d.variantCount >= 8 { break; }
|
if d.variantCount >= 9 { break; }
|
||||||
if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; }
|
if parserCheck(p, tkNewLine) || parserCheck(p, tkSemicolon) { discard parserAdvance(p); continue; }
|
||||||
let vName: LexToken = parserExpect(p, tkIdent, "expected variant name");
|
let vName: LexToken = parserExpect(p, tkIdent, "expected variant name");
|
||||||
|
|
||||||
@@ -1882,6 +1891,7 @@ func parserParseEnumDecl(p: *Parser, isPublic: bool) -> *Decl {
|
|||||||
else if d.variantCount == 5 { d.variant5 = v; }
|
else if d.variantCount == 5 { d.variant5 = v; }
|
||||||
else if d.variantCount == 6 { d.variant6 = v; }
|
else if d.variantCount == 6 { d.variant6 = v; }
|
||||||
else if d.variantCount == 7 { d.variant7 = v; }
|
else if d.variantCount == 7 { d.variant7 = v; }
|
||||||
|
else if d.variantCount == 8 { d.variant8 = v; }
|
||||||
d.variantCount = d.variantCount + 1;
|
d.variantCount = d.variantCount + 1;
|
||||||
|
|
||||||
parserMatch(p, tkComma);
|
parserMatch(p, tkComma);
|
||||||
|
|||||||
+2
-1
@@ -490,7 +490,7 @@ func Sema_CollectGlobals(sema: *Sema) {
|
|||||||
|
|
||||||
// Register enum variants as constants
|
// Register enum variants as constants
|
||||||
var vi: int = 0;
|
var vi: int = 0;
|
||||||
while vi < decl.variantCount && vi < 8 {
|
while vi < decl.variantCount && vi < 9 {
|
||||||
var v: EnumVariant;
|
var v: EnumVariant;
|
||||||
if vi == 0 { v = decl.variant0; }
|
if vi == 0 { v = decl.variant0; }
|
||||||
else if vi == 1 { v = decl.variant1; }
|
else if vi == 1 { v = decl.variant1; }
|
||||||
@@ -500,6 +500,7 @@ func Sema_CollectGlobals(sema: *Sema) {
|
|||||||
else if vi == 5 { v = decl.variant5; }
|
else if vi == 5 { v = decl.variant5; }
|
||||||
else if vi == 6 { v = decl.variant6; }
|
else if vi == 6 { v = decl.variant6; }
|
||||||
else if vi == 7 { v = decl.variant7; }
|
else if vi == 7 { v = decl.variant7; }
|
||||||
|
else if vi == 8 { v = decl.variant8; }
|
||||||
if v.name == null as String || String_Eq(v.name, "") {
|
if v.name == null as String || String_Eq(v.name, "") {
|
||||||
vi = vi + 1;
|
vi = vi + 1;
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
Reference in New Issue
Block a user