- Lexer (Nim + Bux): resolve escape sequences (\n, \t, \r, etc) instead of
keeping raw source text in token. This was the root cause of \n being
double-escaped to \\n in generated C code.
- Manifest parser (src_bux/manifest.bux): use bux_strlen instead of broken
String_SplitCount(s, "") hack for string length; fix quote stripping.
- CLI (src_bux/cli.bux): --version/--help now recognized alongside version/help.
- Remove ~30+ debug Print statements from cli, parser, lexer, sema, main.
- Clean up unneeded Print/PrintInt extern declarations.
- _selfhost/src/: synced from src_bux/.
- Fix segfault from uninitialized Symbol structs in scope/hir_lower/sema
- Fix null ReadFile crash in Cli_MergeFileInto (missing stdlib files)
- Extend function params from 6 to 9 (bux_str_format needs 9 args)
- Add ExprList/HirArgList linked lists for >2 call arguments
- Add banner image to README
- Update docs: C backend is now primary (not QBE)
Major changes:
- Cli_BuildProject now uses CBackend_Generate instead of QBE SSA generation
- Replaced QBE invocation (vendor/qbe/qbe) with direct cc compilation
- Cli_Build (single-file) now compiles C output with cc including runtime.c/io.c
- Added import-based stdlib merging: only imported Std::* modules are merged,
eliminating unused generic code from Array/Map/Set/Channel in simple programs
C backend fixes:
- Fixed struct typedef redefinition: struct definitions now use 'struct Name {}'
instead of 'typedef struct {} Name' to avoid conflicting with forward typedefs
- Added enum support: HirEnum struct, enum emission in C backend, variant
constants emitted as #define Name_Value
- Added char8 typedef
- Skip generic structs/functions (T/K/V type parameters) in C emission
Sema fixes:
- Fixed Sema_IsNumeric: now correctly recognizes uint, float32, float64
- Fixed return type check: allow pointer compatibility (String <-> *T)
Tested: hello, fibonacci, factorial, enums examples build and run via buxc2
- Iterate function body statements and call Sema_CheckStmt on each
- Add Sema_CheckBlock helper for child scope creation in if/while/for/loop blocks
- Extend Sema_CheckStmt to handle all statement kinds: skIf, skWhile, skDoWhile,
skLoop, skFor, skMatch, skBreak, skContinue, skDecl, skReturn
- Extend Sema_CheckExpr with ekAssign, ekField, ekIndex, ekBlock, ekSelf
- Fix ekCall to resolve return type from function declaration
- Fix ekBinary to handle assignment operators (tkAssign, +=, -=, etc.)
- Add Sema_CollectGlobals handling for dkUse (imports), dkConst, dkEnum variants
- Add tkColonColon path parsing in parser (Color::Red)
- Add decl field to Symbol struct for function/type resolution
- Add Sema_ZeroInitSymbol helper to avoid garbage from uninitialized struct fields
- Fix concurrency.bux missing Task_Join import
All examples now pass buxc2 check. make selfhost succeeds.
- QBE_IsTerminator(hBlock) checks ALL children, not just last
- Removed legacy c_backend.bux and nim_backend.bux from _selfhost/src/
- QBE self-hosting QBE phase: PASSES (SSA valid, assembled to .s)
- Remaining: linker errors from missing String_Eq/StringBuilder in runtime
The self-hosted compiler crashed with SIGSEGV when processing files
that generated >=256 parser diagnostics (e.g. truncated source files).
The parser allocated a fixed-size diag buffer of 256 entries, but
parserExpect, parserExpectIdentOrKeyword, and parserEmitDiag wrote
into it without checking bounds. Once diagCount exceeded 256, writes
overflowed into adjacent heap objects (Decl structs), corrupting
their kind/childDecl2 fields and causing crashes during AST traversal.
This fix adds bounds checks to all three sites so excess diagnostics
are silently dropped rather than corrupting memory. The file size
threshold (7037 vs 7062 bytes) was a red herring — it determined
how many parser errors were generated before EOF.
Closes: selfhost segfault on 250+ line files
- Fix lexer unterminated char error test (was treating 'a as lifetime)
- Fix parser test sample.bux path for root-dir execution
- Add bux_system() to runtime.c and run command to selfhost CLI
- Switch bux_alloc from malloc to calloc for zero-init
- Fix module flattening in Cli_Check/Cli_Compile to scan full decl list
- Make test passes fully, selfhost builds successfully
- README.md: drop 'inspired by Rux' and 'improves on Rux' language
- PLAN.md: remove Rux from comparison table, milestones, and appendix
- PLAN.md: delete entire Appendix A (Rux Language Reference)
- docs/PHASE8_STRATEGY.md: rephrase without Rux
- docs/Packages.md: drop 'Compatible with Rux.toml spec'
- Parser_Parse: add beforePos safeguard to skip unrecognized tokens
instead of looping forever when parserParseDecl returns null
- Lexer: increase maxTokens 4096 -> 32768; add explicit break on limit
- CLI: null-check ReadFile result before String_Eq
- Nim CLI: add -O2 to cc invocation for faster self-hosted builds
- Fixed module flattening in self-hosted compiler (Cli_Compile now unwraps module wrappers)
- buxc2 check now finds functions in module-wrapped files (token.bux: funcCount=6, Main.bux: funcCount=2)
- Added debug prints to trace lexer.bux timeout and check x segfault
- Remaining issues: lexer.bux hangs in self-hosted pipeline, check x segfaults in runtime
- Added exprSpawnAsync flag to AST ekSpawn
- Sema checks if callee is async and sets the flag
- HIR hSpawn carries spawnAsync flag
- C backend uses bux_task_spawn for non-async (OS threads) and bux_async_spawn for async (coroutines)
- Added concurrency example to test suite
- T[] slices are now fat pointers {data: T*, len: size_t} in C backend
- Added hSliceIndex HIR node for slice indexing (distinct from hIndexPtr for raw pointers)
- Added exprIndexBoundsCheck flag to AST ekIndex
- Sema sets bounds-check flag in @[Checked] functions
- C backend emits Slice_<T> typedefs and compound literals for slice init
- bux_bounds_check() called automatically on slice indexing in @[Checked] funcs
- Unchecked functions allow raw access (C behavior) for performance
- Lexer tokenizes 'a as tkLifetime
- Parser accepts lifetimes in type params <'a> and reference types &'a T / &'a mut T
- AST TypeExpr has refLifetime field for tekRef/tekMutRef
- TypeParam gains isLifetime flag for generic monomorphization
- Sema infers lifetime params as no-op dummy values; unwraps pointee types for params inside refs
- HIR lower skips lifetime params when generating mangled names and substitution tables
- &mut expr syntax supported in parser (consumed as part of unary &)
Self-hosted compiler (buxc2):
- Add async/await/spawn tokens, parsing, HIR, lowering, C emission
- Fix pointer type emission (*T -> T*) in C backend
- Fix sizeof(Type) parsing with parentheses
- Fix import ::{...} infinite loop guard
- Fix int64 emission by avoiding else-if chain workaround
- Add debug-free cli and hir_lower
Bootstrap compiler (Nim):
- Fix critical else-if lowering bug in hir_lower.nim:
when both elseIfs and else block exist, elseIfs were dropped
causing all else-if chains to collapse to if+else only
Runtime:
- Fix bux_async_await memory corruption (don't free in run)
- Add bux_remove_from_ready for safe cleanup
- Fix forward declaration and deduplicate bux_now_ms
Docs & examples:
- Update async.bux example with proper int64 params
- Update README, LanguageRef, Stdlib, PLAN for async features
- Mark Phase 7.10 bootstrap loop as completed
All 27 examples pass. buxc2 check/build work on all examples.
- runtime: bux_async_return(value, size) copies result to task->result
- runtime: bux_async_await returns void* result pointer
- runtime: bux_async_result(handle) to retrieve result
- sema: ekAwait returns *void
- HIR: await lowered to bux_async_await returning *void
- Example: async Compute() -> int with interleaved execution and result await